标签:不能 还原 打开 i++ time note ges 距离 nsis
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 125945 Accepted Submission(s): 33969
4 4 5 S.X. ..X. ..XD .... 3 4 5 S.X. ..X. ...D 0 0 0
这道题可以不剪枝操作,也不会T了!
不懂剪枝的看这里:DFS中的奇偶剪枝学习笔记
这里说下不剪枝的技巧:为了避免多余的边界控制,可以从i=1,j=1开始读迷宫,在读之前将迷宫初始化为全部‘X‘,即都为墙。这样在迷宫读取完毕后,周围就会自动出现一圈‘X‘,这样就可以在搜索的时候只判断遇到‘X‘就return了。
这里贴一下深搜代码,不管剪不剪枝,这一段是可以不用修改的。
1 inline int DFS(int x,int y,int T) 2 { 3 if(mp[x][y]!=‘.‘&&mp[x][y]!=‘S‘)//碰到X即为边界返回 4 return 0; 5 if(T==1)//剩一步时即可判断是否为出口,找到返回1 6 { 7 if(mp[x-1][y]==‘D‘) 8 return 1; 9 if(mp[x+1][y]==‘D‘) 10 return 1; 11 if(mp[x][y-1]==‘D‘) 12 return 1; 13 if(mp[x][y+1]==‘D‘) 14 return 1; 15 return 0; 16 } 17 else 18 { 19 mp[x][y]=‘X‘;//标记走过 20 if(mp[x-1][y]==‘.‘&&DFS(x-1,y,T-1)) 21 return 1; 22 if(mp[x+1][y]==‘.‘&&DFS(x+1,y,T-1)) 23 return 1; 24 if(mp[x][y-1]==‘.‘&&DFS(x,y-1,T-1)) 25 return 1; 26 if(mp[x][y+1]==‘.‘&&DFS(x,y+1,T-1)) 27 return 1; 28 mp[x][y]=‘.‘;//还原走过 29 return 0; 30 } 31 return 0; 32 }
关于奇偶剪枝
首先举个例子,有如下4*4的迷宫,‘.‘为可走路段,‘X‘为障碍不可通过
S...
....
....
...D
从S到D的最短距离为两点横坐标差的绝对值+两点纵坐标差的绝对值 = abs(Sx - Dx) + abs(Sy - Dy) = 6,这个应该是显而易见的。
遇到有障碍的时候呢
S.XX
X.XX
...X
...D
你会发现不管你怎么绕路,最后从S到达D的距离都是最短距离+一个偶数,这个是可以证明的
而我们知道:
奇数 + 偶数 = 奇数
偶数 + 偶数 = 偶数
因此不管有多少障碍,不管绕多少路,只要能到达目的地,走过的距离必然是跟最短距离的奇偶性是一致的。
所以如果我们知道从S到D的最短距离为奇数,那么当且仅当给定的步数T为奇数时,才有可能走到。如果给定的T的奇偶性与最短距离的奇偶性不一致,那么我们就可以直接判定这条路线永远不可达了。
这里还有个小技巧,我们可以使用按位与运算来简化奇偶性的判断。我们知道1的二进制是1,而奇数的二进制最后一位一定是1,而偶数的二进制最后一位一定是0。所以如果数字&1的结果为1,那么数字为奇数,反之为偶数。
下面给出奇偶剪枝后的main函数代码:
1 int main() 2 { 3 int sx,sy,dx,dy; 4 int N,M,T; 5 while(scanf("%d%d%d",&N,&M,&T)&&N&&M&&T) 6 { 7 getchar(); 8 memset(mp,‘X‘,sizeof(mp));//把周围边界全部变成X 9 for(int i=1;i<=N;i++)//从1开始读,留出边界位置 10 { 11 for(int j=1;j<=M;j++) 12 { 13 scanf("%c",&mp[i][j]); 14 if(mp[i][j]==‘S‘) 15 { 16 sx=i; 17 sy=j; 18 } 19 else if(mp[i][j]==‘D‘) 20 { 21 dx=i; 22 dy=j; 23 } 24 } 25 getchar(); 26 } 27 if((abs(sx-dx)+abs(sy-dy)-T)&1)//奇偶剪枝,对1用按位与运算求奇偶 28 printf("NO\n"); 29 else if(DFS(sx,sy,T)==1) 30 printf("YES\n"); 31 else printf("NO\n"); 32 } 33 return 0; 34 }
所以完整的AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 char mp[15][15]; 4 inline int DFS(int x,int y,int T) 5 { 6 if(mp[x][y]!=‘.‘&&mp[x][y]!=‘S‘)//碰到X即为边界返回 7 return 0; 8 if(T==1)//剩一步时即可判断是否为出口,找到返回1 9 { 10 if(mp[x-1][y]==‘D‘) 11 return 1; 12 if(mp[x+1][y]==‘D‘) 13 return 1; 14 if(mp[x][y-1]==‘D‘) 15 return 1; 16 if(mp[x][y+1]==‘D‘) 17 return 1; 18 return 0; 19 } 20 else 21 { 22 mp[x][y]=‘X‘;//标记走过 23 if(mp[x-1][y]==‘.‘&&DFS(x-1,y,T-1)) 24 return 1; 25 if(mp[x+1][y]==‘.‘&&DFS(x+1,y,T-1)) 26 return 1; 27 if(mp[x][y-1]==‘.‘&&DFS(x,y-1,T-1)) 28 return 1; 29 if(mp[x][y+1]==‘.‘&&DFS(x,y+1,T-1)) 30 return 1; 31 mp[x][y]=‘.‘;//还原走过 32 return 0; 33 } 34 return 0; 35 } 36 int main() 37 { 38 int sx,sy,dx,dy; 39 int N,M,T; 40 while(scanf("%d%d%d",&N,&M,&T)&&N&&M&&T) 41 { 42 getchar(); 43 memset(mp,‘X‘,sizeof(mp));//把周围边界全部变成X 44 for(int i=1;i<=N;i++)//从1开始读,留出边界位置 45 { 46 for(int j=1;j<=M;j++) 47 { 48 scanf("%c",&mp[i][j]); 49 if(mp[i][j]==‘S‘) 50 { 51 sx=i; 52 sy=j; 53 } 54 else if(mp[i][j]==‘D‘) 55 { 56 dx=i; 57 dy=j; 58 } 59 } 60 getchar(); 61 } 62 if((abs(sx-dx)+abs(sy-dy)-T)&1)//奇偶剪枝,对1用按位与运算求奇偶 63 printf("NO\n"); 64 else if(DFS(sx,sy,T)==1) 65 printf("YES\n"); 66 else printf("NO\n"); 67 } 68 return 0; 69 }
HDU 1010 Tempter of the Bone【DFS经典题+奇偶剪枝详解】
标签:不能 还原 打开 i++ time note ges 距离 nsis
原文地址:http://www.cnblogs.com/ECJTUACM-873284962/p/7219300.html