YES
唉。。一道DFS题目,也可以BFS解。这道题今天搞了一天,有些小悲催。。
刚开始不知道怎么想的,用递归总是超时,最后都出现了栈溢出的错误提示。。。
后来就一直WA。。。好崩溃的说。
最后决定用栈来解这道题目,但发现在判定是否走过的路的数组上出现了问题。
就是你走过的路可以置1,但是当你发现这条路走不通时,如何把走过的路置回0呢?
我没想出来,后来看到别人用队列做的,但他的判断数组设置成了3维的,
最后又加了一个来看 某一点4个方向是否都遍历到,遍历过的置1,这样就避免重复走同一条路的情况。
我最后还是决定用递归做了,恩。。AC后发现7000+MS,跟人家0MS 的比快哭了的说。。
后来,看了看别人的剪枝,放到自己代码上,结果骤减到62MS ( ⊙o⊙ )!!!!
搜索的精髓果然还是在剪枝上啊!!
这道题难点就在于如何判断转向上,我是设置的dis数组上右下左(0,1,2,3),可以发现 i对2取模,为0时判定是上下走,为1时判定左右走,这样根据之前的方向和现在的方向就可以知道是否转向了。
强大的剪枝就是:
当转向2次后,来判定当前的点和终点 是否在同一条线路,如果不在同一条线路就直接返回。
代码:
#include <stdio.h> #include <string.h> int map[1005][1005],vis[1005][1005]; int dis[4][2]={-1,0,0,1,1,0,0,-1}; int n,m,f_x,f_y; bool ispos; // dfs开始 void dfs(int x,int y,int direct,int turn) { // 如果转向大于2 或者 已经找到了 则直接返回 if(turn>2 || ispos==1) return; // 如果到了目标,直接判定可以连接,因为之前转向大于2的都返回了 if(x==f_x && y==f_y) { ispos=true; return; } // 强大的剪枝啊=。= if(turn==2) { if(x!=f_x && y!=f_y) return; else if(x==f_x) if(direct!=1) return; else if(y==f_y) if(direct!=0) return; } int i,xx,yy; // 四个方向的遍历 for(i=0;i<4;++i) { xx=x+dis[i][0]; yy=y+dis[i][1]; // 边界判定 if(xx<1 || yy<1 || xx>n || yy>m || vis[xx][yy]==1) continue; // 如果下一个点是0或者终点 if(map[xx][yy]==0 || (xx==f_x && yy==f_y)) { vis[xx][yy]=1; //根据原来的方向来确定是否转向 if(direct==-1) dfs(xx,yy,i%2,turn); else if(direct==0) { if(i%2==1) dfs(xx,yy,1,turn+1); else dfs(xx,yy,0,turn); } else if(direct==1) { if(i%2==0) dfs(xx,yy,0,turn+1); else dfs(xx,yy,1,turn); } vis[xx][yy]=0; } } } int main() { int i,j,q,s_x,s_y; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0 && m==0) break; // 输入 for(i=1;i<=n;++i) for(j=1;j<=m;++j) scanf("%d",&map[i][j]); scanf("%d",&q); while(q--) { scanf("%d%d%d%d",&s_x,&s_y,&f_x,&f_y); // 如果搜寻的两个点不相等或者搜寻的点是空点(即搜寻的点有0) if(map[s_x][s_y]!=map[f_x][f_y] || map[s_x][s_y]==0 ) { printf("NO\n"); continue; } // 如果搜寻两个点都为本身(去掉后增加了点时间) if(s_x==f_x && s_y == f_y && map[s_x][s_y]!=0) { printf("NO\n"); continue; } // 初始化 memset(vis,0,sizeof(vis)); ispos=false; dfs(s_x,s_y,-1,0); // 判断输出 if(ispos) printf("YES\n"); else printf("NO\n"); } } return 0; }
还有WA的可能就是因为方向的问题。。。
提供一组别人想的测试数据: