题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3713
题目:两个小球同时在两个迷宫里走,求使两个小球同时到达终点的最短走法。小球不能越出迷宫界,也不能掉到洞里。有的格子有挡板,如果挡板阻碍了小球的移动,则小球会呆在原地不动。如果有多组解,输出字典序最小的那个。
分析:裸BFS,但是我错了很多遍,因为之前有些地方没想清楚。
1,一开始我把 [小球被挡板阻碍] 和 [小球越界,小球掉到洞里] 放到一起考虑,写了个判断,都认为它们是不可达的。这是错误的。实际上这是两种情况,因为题目中有说:The barriers may make the commands take no effect, i.e., the ball does NOT move if there is a barrier on the way. 挡板只是抵消了这一步的命令,它可以继续执行下一步命令,并不是不可达。而[小球越界,小球掉到洞里] 才是不可达的情况。所以应当先判断这一步命令对两个小球是否分别有效,再判断它们是否越界或掉到洞里。
2,在判断小球能否移动到下一个格子上,有一个比较坑爹的地方。
举例说明:如果小球所在的格子是A,B是A正上方的格子,若A上方有挡板,那么它是不能由A直接向上移动到B。
我是先把小球移动到B,再判断B正下方是否有挡板,若有,则它是不能由A直接向上移动到B。
按理说这两种判断方式应该是一样的,也就是说,A上方有挡板=B下方有挡板。但事实上只有第一种判断方法是正确的,第二种是错误的,我WA了好几次才该对。
也就是说A上方有挡板≠B下方有挡板,至于为啥,貌似题目里面也没说清楚。
1 #include <cstdio> 2 #include <cstring> 3 4 const int MAXN = 8; 5 const int MAXSIZE = 10000 + 1; 6 const char move[5] = "DLRU"; //保证字典序最小 7 const int dx[] = { 1, 0, 0, -1 }; 8 const int dy[] = { 0, -1, 1, 0 }; 9 10 int map1[MAXN][MAXN]; 11 int map2[MAXN][MAXN]; 12 int start_x1, start_y1, start_x2, start_y2; 13 int fa[MAXSIZE]; //记录移动路线 14 bool vis[MAXSIZE]; //判重 15 int queue[MAXSIZE]; //队列 16 int dir[MAXSIZE]; //记录移动方向 17 char answer[MAXSIZE]; //记录答案 18 19 int GetHash( int a, int b, int c, int d ) 20 { 21 return a * 1000 + b * 100 + c * 10 + d; 22 } 23 24 bool check( int x, int y, int dirc, int (*map)[8] ) //判断是否移动成功 25 { 26 if ( dirc == 3 && (( map[x][y] >> 3 ) & 1 )) return false; 27 if ( dirc == 2 && (( map[x][y] >> 2 ) & 1 )) return false; 28 if ( dirc == 1 && ( map[x][y] & 1 ) ) return false; 29 if ( dirc == 0 && (( map[x][y] >> 1 ) & 1 )) return false; 30 return true; 31 } 32 33 bool in( int x, int y, int (*map)[8] ) //判断是否越界,是否掉到洞里 34 { 35 if ( x >= 1 && x <= 6 && y >= 1 && y <= 6 ) return ( ( map[x][y] >> 4 ) & 1 ); 36 return false; 37 } 38 39 int BFS() 40 { 41 //初始化 42 memset( vis, false, sizeof(vis) ); 43 44 int front = 0, rear = 0; 45 int hash = GetHash( start_x1, start_y1, start_x2, start_y2 ); 46 queue[ rear++ ] = hash; //头结点入队 47 vis[hash] = true; 48 fa[hash] = 0; 49 50 while ( front < rear ) 51 { 52 int temp = queue[front]; 53 54 int x1 = temp / 1000; 55 int y1 = ( temp / 100 ) % 10; 56 int x2 = ( temp / 10 ) % 10; 57 int y2 = temp % 10; 58 59 if ( ( ( map1[x1][y1] >> 6 ) & 1 ) && ( ( map2[x2][y2] >> 6 ) & 1 ) ) return temp; //判断终点 60 61 for ( int i = 0; i < 4; i++ ) //四方向移动 62 { 63 int xx1 = x1; 64 int yy1 = y1; 65 66 if ( check(xx1, yy1, i, map1) ) 67 { 68 xx1 += dx[i]; 69 yy1 += dy[i]; 70 } 71 72 int xx2 = x2; 73 int yy2 = y2; 74 75 if ( check(xx2, yy2, i, map2) ) 76 { 77 xx2 += dx[i]; 78 yy2 += dy[i]; 79 } 80 81 if ( !in(xx1, yy1, map1) || !in( xx2, yy2, map2 ) ) continue; 82 83 hash = GetHash( xx1, yy1, xx2, yy2 ); 84 85 if ( !vis[hash] ) //如果该节点尚未访问,插入队列 86 { 87 queue[ rear++ ] = hash; 88 fa[hash] = temp; 89 dir[hash] = i; 90 vis[hash] = true; 91 } 92 } 93 ++front; 94 } 95 return -1; //如果查找失败,返回-1 96 } 97 98 int main() 99 { 100 int T; 101 scanf( "%d", &T ); 102 for ( int i = 1; i <= 6; i++ ) 103 for ( int j = 1; j <= 6; j++ ) 104 { 105 scanf( "%d", &map2[i][j] ); 106 if ( ( map2[i][j] >> 5 ) & 1 ) 107 { 108 start_x2 = i; 109 start_y2 = j; 110 } 111 } 112 113 --T; 114 while ( T-- ) 115 { 116 memcpy( map1, map2, sizeof(map1) ); 117 start_x1 = start_x2; 118 start_y1 = start_y2; 119 120 for ( int i = 1; i <= 6; i++ ) 121 for ( int j = 1; j <= 6; j++ ) 122 { 123 scanf( "%d", &map2[i][j] ); 124 if ( ( map2[i][j] >> 5 ) & 1 ) 125 { 126 start_x2 = i; 127 start_y2 = j; 128 } 129 } 130 131 int ans = BFS(); 132 if ( ans == -1 ) puts("-1"); 133 else 134 { 135 int k = -1; 136 for( int i = ans; fa[i] != 0; i = fa[i] ) 137 answer[ ++k ] = move[ dir[i] ]; 138 139 for ( ; k >= 0; k-- ) putchar( answer[k] ); 140 putchar('\n'); 141 } 142 } 143 return 0; 144 }