直接以(0,0)广搜,判断是否能到(0,1)(0,-1)(1,0)(-1,0)但直接这样做复杂度过高,需要利用以下剪枝。
1. 限制在(-100..100,-100..100)内移动
2. 移动到一个点(x,y)时,判断(-x,-y)周围是否已到达
3. 一旦判断成功,立即退出
第一点剪枝的正确性本人尚不明
第二点剪枝还是很妙的 不过没写
几年前做的题 连代码是不是自己写的都不记得了 如果发现雷同代码 请随意鄙视我
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
const int sumpoints = 40401;
int T, n;
int dx[101], dy[101];
bool vis[201][201];
inline int gcd(int a,int b){
if (a<b) return gcd(b,a);
if (b==0) return a;
return gcd(b,a%b);
}
struct pnt {
int x, y;
pnt(int x = 100, int y = 100) :x(x), y(y) {}
};
bool bfs() {
queue <pnt> q;
q.push(pnt());
vis[100][100] = true;
pnt u;
while(!q.empty()) {
u = q.front();
q.pop();
for(int i = 1; i <= n; ++i) {
u.x += dx[i]; u.y += dy[i];
if(u.x>=0 && u.x<=200 && u.y>=0 && u.y<=200)
if(!vis[u.x][u.y]) {
q.push(u);
vis[u.x][u.y] = true;
if(vis[100][99] && vis[100][101] && vis[99][100] && vis[101][100])
return true;
}
u.x -= dx[i]; u.y -= dy[i];
}
}
if(vis[100][99] && vis[100][101] && vis[99][100] && vis[101][100]) return true;
else return false;
}
int main() {
freopen("t.in", "r", stdin);
freopen("t.out", "w", stdout);
scanf("%d", &T);
while(T--) {
memset(dx, 0, sizeof(dx));
memset(dy, 0, sizeof(dy));
memset(vis, false, sizeof(vis));
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d%d", &dx[i], &dy[i]);
if (n>=2){
int G=gcd(abs(dx[1]),abs(dx[2]));
for (int i=3;i<=n;i++)
G=gcd(G,abs(dx[i]));
if (G>1) { puts("NIE"); continue; }
G=gcd(abs(dy[1]),abs(dy[2]));
for (int i=3;i<=n;i++)
G=gcd(G,abs(dy[i]));
if (G>1) { puts("NIE"); continue; }
}
if(bfs()) puts("TAK");
else puts("NIE");
}
return 0;
}


1169

被折叠的 条评论
为什么被折叠?



