poj2251:Dungeon Master
最初没有注意到结果是要求最小的步数,那么就成了最基本的迷宫找到一条出路的问题并记下找到出路时,所花的步数,那么很容易得到代码如下:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 6 #define MAX 1000000 7 int l,r,c,coun; 8 char m[30][30][30]; 9 bool flag[30][30][30]; 10 int num[30][30][30]={0}; 11 void work(int i,int j,int level,int mins) 12 { 13 //flag[level][i][j] = false; 14 num[level][i][j] = mins; 15 if(mins >= coun) 16 return ; 17 if(m[level][i][j] == 'E') 18 { 19 coun = mins; 20 return ; 21 } 22 23 if(level < l-1) 24 { 25 if((flag[level+1][i][j] == true) && (num[level+1][i][j] == 0 || mins+1 < num[level+1][i][j])) 26 work(i,j,level+1,mins+1); 27 } 28 if(level > 0) 29 { 30 if(flag[level-1][i][j] == true&& (num[level-1][i][j] == 0 || mins+1 < num[level-1][i][j])) 31 work(i,j,level-1,mins+1); 32 } 33 if(i < r-1) 34 { 35 if(flag[level][i+1][j] == true&& (num[level][i+1][j] == 0 || mins+1 < num[level][i+1][j])) 36 work(i+1,j,level,mins+1); 37 } 38 if(i > 0) 39 { 40 if(flag[level][i-1][j] == true&& (num[level][i-1][j] == 0 || mins+1 < num[level][i-1][j])) 41 work(i-1,j,level,mins+1); 42 } 43 if(j < c-1) 44 { 45 if(flag[level][i][j+1] == true&& (num[level][i][j+1] == 0 || mins+1 < num[level][i][j+1])) 46 work(i,j+1,level,mins+1); 47 } 48 if(j > 0) 49 { 50 if(flag[level][i][j-1] == true&& (num[level][i][j-1] == 0 || mins+1 < num[level][i][j-1])) 51 work(i,j-1,level,mins+1); 52 } 53 } 54 55 int main() 56 { 57 while(cin>>l>>r>>c) 58 { 59 if(l == 0 && r == 0 && c == 0) 60 break; 61 int startl,starti,startj; 62 char s; 63 scanf("%c",&s); 64 for(int i = 0; i < l; i++ ) 65 { 66 for(int j = 0; j < r; j++) 67 { 68 for(int k = 0; k < c; k++) 69 { 70 scanf("%c",&m[i][j][k]); 71 if(m[i][j][k] == 'S') 72 { 73 startl = i; 74 starti = j; 75 startj = k; 76 } 77 if(m[i][j][k] == '#') 78 flag[i][j][k] = false; 79 else 80 flag[i][j][k] = true; 81 } 82 scanf("%c",&s); 83 } 84 scanf("%c",&s); 85 } 86 /*for(int i = 0; i < l; i++ ) 87 { 88 for(int j = 0; j < r; j++) 89 { 90 for(int k = 0; k < c; k++) 91 { 92 printf("%c",m[i][j][k]); 93 } 94 printf("\n"); 95 } 96 printf("\n"); 97 }*/ 98 coun = MAX; 99 memset(num,0,sizeof(num)); 100 work(starti,startj,startl,0); 101 if(coun < MAX) 102 printf("Escaped in %d minute(s).\n", coun); 103 else 104 printf("Trapped!\n"); 105 } 106 return 0; 107 }
注意到之后,那么bool 属性的flag其实就不必了,我在下文代码中的flag其实只是用来判断那个点是否是‘#’字符而已,没什么用,必须遍历所有情况才能够找出最小步数,那么就只需要剪枝就好了。
最开始,我注意到的剪枝方法就是最简单的,只有一个返回条件:
1.当前的步数已经超过最小的通过迷宫的步数的时候,返回。
结果发现无限循环了。。。想了一想,因为并没有限制重复的搜索,所以一直在无限制的重复搜索下去了。
那么加上第二个剪枝条件来防止无限制地重复搜索:
2.当下一步要访问的点之前已经访问过的时候,而且如果要访问的话,之前访问到该点的步数小于或者等于当前情况访问到该点的步数,则不再去访问。
按照这个思路,写完代码提交过后,又出现了超时。。。
则加上第三个剪枝条件,实质上是加强了第一个条件:
当前访问到的点已经经过的步数加上到达出口所需的最短步数已经超过 之前计算出的通过迷宫所需的最短步数时,则返回。
终于AC了!现在献上AC代码
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 #include <stdlib.h> 6 using namespace std; 7 8 #define MAX 1000000 9 int l,r,c,coun; 10 char m[30][30][30]; 11 bool flag[30][30][30]; 12 int num[30][30][30]={0}; 13 int startl,starti,startj,endle,endi,endj; 14 void work(int i,int j,int level,int mins) 15 { 16 //flag[level][i][j] = false; 17 num[level][i][j] = mins; 18 if(mins+abs(i-endi)+abs(j-endj)+abs(level-endle) >= coun) 19 return ; 20 if(m[level][i][j] == 'E') 21 { 22 coun = mins; 23 return ; 24 } 25 26 if(level < l-1) 27 { 28 if((flag[level+1][i][j] == true) && (num[level+1][i][j] == 0 || mins+1 < num[level+1][i][j])) 29 work(i,j,level+1,mins+1); 30 } 31 if(level > 0) 32 { 33 if(flag[level-1][i][j] == true&& (num[level-1][i][j] == 0 || mins+1 < num[level-1][i][j])) 34 work(i,j,level-1,mins+1); 35 } 36 if(i < r-1) 37 { 38 if(flag[level][i+1][j] == true&& (num[level][i+1][j] == 0 || mins+1 < num[level][i+1][j])) 39 work(i+1,j,level,mins+1); 40 } 41 if(i > 0) 42 { 43 if(flag[level][i-1][j] == true&& (num[level][i-1][j] == 0 || mins+1 < num[level][i-1][j])) 44 work(i-1,j,level,mins+1); 45 } 46 if(j < c-1) 47 { 48 if(flag[level][i][j+1] == true&& (num[level][i][j+1] == 0 || mins+1 < num[level][i][j+1])) 49 work(i,j+1,level,mins+1); 50 } 51 if(j > 0) 52 { 53 if(flag[level][i][j-1] == true&& (num[level][i][j-1] == 0 || mins+1 < num[level][i][j-1])) 54 work(i,j-1,level,mins+1); 55 } 56 } 57 58 int main() 59 { 60 while(cin>>l>>r>>c) 61 { 62 if(l == 0 && r == 0 && c == 0) 63 break; 64 65 char s; 66 scanf("%c",&s); 67 for(int i = 0; i < l; i++ ) 68 { 69 for(int j = 0; j < r; j++) 70 { 71 for(int k = 0; k < c; k++) 72 { 73 scanf("%c",&m[i][j][k]); 74 if(m[i][j][k] == 'S') 75 { 76 startl = i; 77 starti = j; 78 startj = k; 79 } 80 if(m[i][j][k] == 'E') 81 { 82 endle = i; 83 endi = j; 84 endj = k; 85 } 86 if(m[i][j][k] == '#') 87 flag[i][j][k] = false; 88 else 89 flag[i][j][k] = true; 90 } 91 scanf("%c",&s); 92 } 93 scanf("%c",&s); 94 } 95 /*for(int i = 0; i < l; i++ ) 96 { 97 for(int j = 0; j < r; j++) 98 { 99 for(int k = 0; k < c; k++) 100 { 101 printf("%c",m[i][j][k]); 102 } 103 printf("\n"); 104 } 105 printf("\n"); 106 }*/ 107 coun = MAX; 108 memset(num,0,sizeof(num)); 109 work(starti,startj,startl,0); 110 if(coun < MAX) 111 printf("Escaped in %d minute(s).\n", coun); 112 else 113 printf("Trapped!\n"); 114 } 115 return 0; 116 }