HDOJ 1175 连连看 DFS
这题在DFS的同时必须考虑剪枝,,给出三个别人的代码,一个耗时7秒多,一个2秒多,最后一个只有46MS,相差甚大,都是剪枝的功劳。
1 #include <stdio.h> 2 #include <string.h> 3 const int MAX =1002; 4 bool flag = false; 5 bool vist[MAX][MAX]; 6 int s,e,map[MAX][MAX]; 7 int dir[5][3]={{1,0},{0,1},{-1,0},{0,-1}}; 8 void DFS(int x,int y,int cnt,int d) 9 { 10 if(cnt>2||vist[x][y]||flag)return; 11 vist[x][y] = true; 12 for(int i = 0;i < 4;i++) 13 { 14 int a,b,t; 15 a = x + dir[i][0]; 16 b = y + dir[i][1]; 17 if(d!=i) t = cnt +1; 18 else t = cnt; 19 if(a==s&&b==e&&t<=2) 20 {flag = true;return ;} //printf("x-%d y-%d a-%d b-%d\n",x,y,a,b); 21 if(!map[a][b]&&!vist[a][b]) 22 DFS(a,b,t,i); 23 } 24 vist[x][y] = false; 25 } 26 int main() 27 { 28 //freopen("Input.txt","r",stdin); 29 //freopen("Output.txt","w",stdout); 30 int n,m,u,v,q; 31 while(scanf("%d%d",&n,&m),(n||m)) 32 { 33 memset(map,-1,sizeof(map)); 34 for(int i = 1;i <= n;i++) 35 for(int j = 1;j <= m;j++) 36 scanf("%d",&map[i][j]); 37 scanf("%d",&q); 38 while(q--) 39 { 40 scanf("%d%d%d%d",&u,&v,&s,&e); 41 flag = false; 42 memset(vist,false,sizeof(vist)); 43 if(map[u][v]!=map[s][e]||map[u][v]==0); 44 else 45 DFS(u,v,-1,-1); 46 if(flag) 47 puts("YES"); 48 else 49 puts("NO"); 50 } 51 } 52 return 0; 53 }
//【解题思路】:dfs+剪枝。其实没什么好说的,有几个要注意的地方,第一个是判重,第二个是记住最多仅能够进行两次转向。切记,在判断到达目标的时候,需要判断其转向次数是否超过两次,表示个人在此处wa了两次。 纯暴力版过了之后。有一个剪枝是:在转向两次之后,因为不可转向,所以接下来必须与之前的方式保持一致,这个优化减少了5s左右的时间,原先是7000ms,现在是2000ms。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <cmath> #include <string> #include <cctype> #include <map> #include <iomanip> using namespace std; #define eps 1e-8 #define pi acos(-1.0) #define pb push_back #define lc(x) (x << 1) #define rc(x) (x << 1 | 1) #define lowbit(x) (x & (-x)) #define ll long long int stx[4]={-1,0,1,0}; int sty[4]={0,1,0,-1}; int a[1100][1100]; int vis[1100][1100]; int n,m,x,y,xx,yy,q,tmp; bool flag; bool solve(int x,int y,int xx,int yy,int cnt,int dir){ int tx,ty; if (x==xx && y==yy && cnt<=2) {return true;} if (a[x][y]!=0 && cnt!=-1) return false; if (cnt>2) return false; else { if (cnt==2){ //优化部分 vis[x][y]=tmp; tx=x+stx[dir]; ty=y+sty[dir]; if (tx>=0 && tx<n && ty>=0 && ty<m && vis[tx][ty]!=tmp){ if (solve(tx,ty,xx,yy,cnt,dir)) return true; } vis[x][y]=0; } //end else{ vis[x][y]=tmp; for (int i=0; i<4; i++){ tx=x+stx[i]; ty=y+sty[i]; if (tx>=0 && tx<n && ty>=0 && ty<m && vis[tx][ty]!=tmp){ if (cnt==-1) {if (solve(tx,ty,xx,yy,cnt+1,i)) return true;} else {if (i!=dir) {if (solve(tx,ty,xx,yy,cnt+1,i)) return true;} else {if (solve(tx,ty,xx,yy,cnt,dir)) return true;} } } } vis[x][y]=0; } } return false; } int main() { while (~scanf("%d%d",&n,&m)){ if (n==0 && m==0) break; for (int i=0; i<n; i++){ for (int j=0; j<m; j++) scanf("%d",&a[i][j]); } memset(vis,0,sizeof(vis)); scanf("%d",&q); for (int i=1; i<=q; i++){ scanf("%d%d%d%d",&x,&y,&xx,&yy); x--; y--; xx--; yy--; tmp=i; vis[x][y]=tmp; if (a[xx][yy]!=a[x][y] || (a[x][y]==a[xx][yy] && a[x][y]==0)) {printf("NO\n"); continue;} if (xx==x && yy==y) {printf("NO\n"); continue;} flag=false; if (solve(x,y,xx,yy,-1,-1)==true) { printf("YES\n"); } else printf("NO\n"); } } return 0; }
/* 本题纯属中文,题意很好理解,主要说下需要注意的几点。。 1。首先需要判断给定的俩个棋子是否相同 2。如果给定的坐标没有棋子直接输出NO 3。如果给定的坐标是同一个,也直接输出NO。。不知道测试数据里有没有这么恶心的数据,不过小心为上吧。。 3。本题搜索需要一点方向感。盲目搜索必定超时,因为本题可以进行俩次转向。。所以可以分为三种情况。我用turn来标记转向的次数 turn=0 则直接进行下一步搜索。 turn=1 则需要判断 状态的方向 dir 是否与 需要寻找的棋子位置反向了。。如果反向则放弃搜索、、 turn=2 则判断是否和目标棋子在一条直线上,而且需要判断方向是否一致。。否则放弃搜索。。 */
/*
46MS | 3236K |
*/
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> using namespace std; int n,m; int move[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; bool used[1005][1005]; int flag; struct State { int x; int y; int dir; int turn; int step; }; State start; State end; int map[1005][1005]; bool Judge(State t) { if(t.x==end.x&&t.y==end.y) return 1; if(t.turn==0) return 1; if(t.turn==1) { if(t.x>end.x&&t.dir==1) return 0; if(t.y>end.y&&t.dir==3) return 0; if(t.x<end.x&&t.dir==0) return 0; if(t.y<end.y&&t.dir==2) return 0; return 1; } if(t.turn==2) { if(t.x==end.x) { if(t.y>end.y&&t.dir==2) return 1; if(t.y<end.y&&t.dir==3) return 1; } if(t.y==end.y) { if(t.x>end.x&&t.dir==0) return 1; if(t.x<end.x&&t.dir==1) return 1; } return 0; } return 1; } void DFS(State t) { if(flag) return; if(t.turn>2) return; if(t.x==end.x&&t.y==end.y) { flag=1; return; } int x,y; State temp; if(t.step==0) { for(int i=0;i<4;i++) { temp.x=t.x+move[i][0]; temp.y=t.y+move[i][1]; if(temp.x<=0||temp.y<=0||temp.x>n||temp.y>m||used[temp.x][temp.y]==1) continue; temp.dir=i; temp.turn=0; temp.step=t.step+1; if(Judge(temp)==0) continue; used[temp.x][temp.y]=1; DFS(temp); used[temp.x][temp.y]=0; } return; } if(map[t.x][t.y]!=0) return; for(int i=0;i<4;i++) { temp.x=t.x+move[i][0]; temp.y=t.y+move[i][1]; if(temp.x<=0||temp.y<=0||temp.x>n||temp.y>m||used[temp.x][temp.y]==1) continue; if(t.dir!=i) { temp.dir=i; temp.turn=t.turn+1; }else { temp.dir=t.dir; temp.turn=t.turn; } temp.step=1; if(Judge(temp)==0) continue; used[temp.x][temp.y]=1; DFS(temp); used[temp.x][temp.y]=0; } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int t; while(scanf("%d %d",&n,&m)) { if(n==0&&m==0) return 0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&map[i][j]); scanf("%d",&t); while(t--) { scanf("%d %d %d %d",&start.x,&start.y,&end.x,&end.y); if(start.x==end.x&&start.y==end.y) { printf("NO\n"); continue; } if(map[start.x][start.y]!=map[end.x][end.y]||map[start.x][start.y]==0||map[end.x][end.y]==0) { printf("NO\n"); continue; } memset(used,0,sizeof(used)); used[start.x][start.y]=1; start.turn=0; start.step=0; flag=0; DFS(start); if(flag) printf("YES\n"); else printf("NO\n"); } } return 0; }