HDU 1728 逃离迷宫
这道题做的我想哭啊。。WA了将近十次了吧
一开始我用数组模拟的队列,后来和老大代码对拍,感觉改的是基本都一模一样了,还是WA
实在没有办法了,改用queue了
题目里的x是列y是行,和代码里的反过来的,要注意!
题目里面说在起点的时候无论朝哪个方向走都不算一次转弯,所以我们将方向和转弯次数都赋值为-1,这样就不用特殊处理了
入队条件,拓展后的转弯次数小于或等于vis数组中记录的最小转弯次数即可入队
输出结果,不要一搜到终点便急着输出,应为可能后面再一次搜到终点的时候转弯次数小于k
因此可以遍历完以后再输出,或者输出yes的时候加一个限制条件:转弯次数小于等于k
两种处理方法,第二种更快一点
这里先把数组WA掉的代码贴上,留着以后再找错。
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 7 struct Point 8 { 9 int x, y; 10 int di, times; 11 }qu[20000 + 10]; 12 13 const int MAX = 200; 14 char map[105][105]; 15 int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 16 int row, col, vis[105][105]; 17 int sx, sy, ex, ey, k; 18 int head, tail; 19 20 bool islegal(int x, int y) 21 { 22 if(x>=0 && x<row && y>=0 && y<col && map[x][y]=='.') 23 return true; 24 return false; 25 } 26 27 void BFS(void) 28 { 29 head = 0, tail = 1; 30 vis[sx][sy] = 0; 31 qu[0].x = sx, qu[0].y = sy; 32 qu[0].di = -1, qu[0].times = -1; 33 while(head < tail) 34 { 35 //if(qu[head].x==ex && qu[head].y==ey) 36 //{printf("yes\n"); return;} 37 for(int i = 0; i < 4; ++i) 38 { 39 int temp; 40 int xx = qu[head].x + dir[i][0]; 41 int yy = qu[head].y + dir[i][1]; 42 if(!islegal(xx, yy)) continue; 43 if(i != qu[head].di) 44 temp = qu[head].times + 1; 45 else 46 temp = qu[head].times; 47 if(temp > k) continue; 48 if(temp <= vis[xx][yy]) 49 { 50 vis[xx][yy] = temp; 51 qu[tail].x = xx, qu[tail].y = yy; 52 qu[tail].di = i; 53 qu[tail++].times = temp; 54 } 55 } 56 ++head; 57 } 58 if(vis[ex][ey] <= k) 59 printf("yes\n"); 60 else 61 printf("no\n"); 62 } 63 64 int main(void) 65 { 66 #ifdef LOCAL 67 freopen("1728in.txt", "r", stdin); 68 #endif 69 70 int T; 71 scanf("%d", &T); 72 while(T--) 73 { 74 scanf("%d%d", &row, &col); 75 getchar(); 76 for(int i = 0; i < row; ++i) 77 { 78 for(int j = 0; j < col; ++j) 79 { 80 scanf("%c", &map[i][j]); 81 vis[i][j] = MAX; 82 } 83 getchar(); 84 } 85 scanf("%d%d%d%d%d", &k, &sy, &sx, &ey, &ex); 86 --sx, --sy, --ex, --ey; 87 BFS(); 88 } 89 return 0; 90 }
queue的AC代码:
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 8 struct Point 9 { 10 int x, y; 11 int di, times; 12 }qu[20000 + 10]; 13 14 const int MAX = 200; 15 char map[105][105]; 16 int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 17 int row, col, vis[105][105]; 18 int sx, sy, ex, ey, k; 19 20 bool islegal(int x, int y) 21 { 22 return(x>=0 && x<row && y>=0 && y<col && map[x][y]=='.'); 23 } 24 25 void BFS(void) 26 { 27 queue<Point> qu; 28 vis[sx][sy] = 0; 29 Point cur; 30 cur.x = sx, cur.y = sy; 31 cur.di = cur.times = -1; 32 qu.push(cur); 33 while(!qu.empty()) 34 { 35 cur = qu.front(); 36 qu.pop(); 37 if(cur.x==ex&&cur.y==ey&&cur.times<=k) 38 { 39 printf("yes\n"); 40 return; 41 } 42 for(int i = 0; i < 4; ++i) 43 { 44 Point next = cur; 45 next.x += dir[i][0]; 46 next.y += dir[i][1]; 47 if(!islegal(next.x, next.y)) continue; 48 if(i != cur.di) 49 { 50 next.di = i; 51 ++next.times; 52 } 53 if(next.times > k) continue; 54 if(next.times <= vis[next.x][next.y]) 55 { 56 vis[next.x][next.y] = next.times; 57 qu.push(next); 58 } 59 } 60 } 61 printf("no\n"); 62 } 63 64 int main(void) 65 { 66 #ifdef LOCAL 67 freopen("1728in.txt", "r", stdin); 68 #endif 69 70 int T; 71 scanf("%d", &T); 72 while(T--) 73 { 74 scanf("%d%d", &row, &col); 75 getchar(); 76 for(int i = 0; i < row; ++i) 77 { 78 for(int j = 0; j < col; ++j) 79 { 80 scanf("%c", &map[i][j]); 81 vis[i][j] = MAX; 82 } 83 getchar(); 84 } 85 scanf("%d%d%d%d%d", &k, &sy, &sx, &ey, &ex); 86 --sx, --sy, --ex, --ey; 87 BFS(); 88 } 89 return 0; 90 }
对比了一下别人的代码,才知道自己写的代码有多么挫。。
http://972169909-qq-com.iteye.com/blog/1244218
这里讲了两种方法,因为题目只是问能不能在转k个弯之内到达,而不是转的最小的弯,所以DFS也是能做的。30MS多点
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 7 const int MAX = 200; 8 char map[105][105]; 9 int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 10 int row, col, vis[105][105]; 11 int sx, sy, ex, ey, k; 12 bool flag; 13 14 bool islegal(int x, int y) 15 { 16 return(x>=0 && x<row && y>=0 && y<col && map[x][y]=='.'); 17 } 18 19 void DFS(int x, int y, int di) 20 { 21 if(x==ex && y==ey && vis[ex][ey]<=k) 22 {flag = true; return;} 23 if(vis[x][y] > k) 24 return; 25 if(x!=ex && y!=ey && vis[x][y]==k) 26 return; 27 for(int i = 0; i < 4; ++i) 28 { 29 int tx = x + dir[i][0]; 30 int ty = y + dir[i][1]; 31 if(!islegal(tx, ty)) 32 continue; 33 if(vis[tx][ty] < vis[x][y]) 34 continue; 35 if(i!=di && vis[tx][ty] < vis[x][y]+1) 36 continue; 37 vis[tx][ty] = vis[x][y]; 38 if(i != di) 39 ++vis[tx][ty]; 40 DFS(tx, ty, i); 41 if(flag) 42 return; 43 } 44 } 45 46 int main(void) 47 { 48 #ifdef LOCAL 49 freopen("1728in.txt", "r", stdin); 50 #endif 51 52 int T; 53 scanf("%d", &T); 54 while(T--) 55 { 56 scanf("%d%d", &row, &col); 57 getchar(); 58 for(int i = 0; i < row; ++i) 59 { 60 for(int j = 0; j < col; ++j) 61 { 62 scanf("%c", &map[i][j]); 63 vis[i][j] = MAX; 64 } 65 getchar(); 66 } 67 scanf("%d%d%d%d%d", &k, &sy, &sx, &ey, &ex); 68 --sx, --sy, --ex, --ey; 69 vis[sx][sy] = -1; 70 flag = false; 71 DFS(sx, sy, -1); 72 if(flag) printf("yes\n"); 73 else printf("no\n"); 74 } 75 return 0; 76 }
下面重头戏来了,解法永远都是只有更好没有最好。博主讲了一个单方向优先扩展的广搜。
把一般的广搜比作一个石子在起点激起一圈圈涟漪,单方向优先的就是向开车一样“横冲直撞”、直来直往。
因为我们是要找转弯次数最小的,因此这样的搜索方式应该也能较快的找到符合条件的路径,运行时间15MS
感觉代码的有些小细节还没有理解透,等以后回过头来慢慢消化
1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 8 struct Point 9 { 10 int x, y; 11 }cur, next; 12 13 const int MAX = 200; 14 char map[105][105]; 15 int dir[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; 16 int row, col, vis[105][105]; 17 int sx, sy, ex, ey, k; 18 19 bool islegal(int x, int y) 20 { 21 return(x>=0 && x<row && y>=0 && y<col && map[x][y]=='.'); 22 } 23 24 void BFS(void) 25 { 26 queue<Point> qu; 27 vis[sx][sy] = -1; 28 Point cur; 29 cur.x = sx, cur.y = sy; 30 qu.push(cur); 31 while(!qu.empty()) 32 { 33 cur = qu.front(); 34 qu.pop(); 35 if(cur.x==ex&&cur.y==ey&&vis[cur.x][cur.y]<=k) 36 { 37 printf("yes\n"); 38 return; 39 } 40 for(int i = 0; i < 4; ++i) 41 { 42 next = cur; 43 next.x += dir[i][0]; 44 next.y += dir[i][1]; 45 while(islegal(next.x, next.y)) 46 { 47 if(vis[next.x][next.y] < vis[cur.x][cur.y] + 1) 48 break; 49 vis[next.x][next.y] = vis[cur.x][cur.y] + 1; 50 if(vis[next.x][next.y] > k) 51 break; 52 if(vis[next.x][next.y] == k && next.x!=ex && next.y!=ey) 53 break; 54 qu.push(next); 55 next.x += dir[i][0]; 56 next.y += dir[i][1]; 57 } 58 } 59 } 60 printf("no\n"); 61 } 62 63 int main(void) 64 { 65 #ifdef LOCAL 66 freopen("1728in.txt", "r", stdin); 67 #endif 68 69 int T; 70 scanf("%d", &T); 71 while(T--) 72 { 73 scanf("%d%d", &row, &col); 74 getchar(); 75 for(int i = 0; i < row; ++i) 76 { 77 for(int j = 0; j < col; ++j) 78 { 79 scanf("%c", &map[i][j]); 80 vis[i][j] = MAX; 81 } 82 getchar(); 83 } 84 scanf("%d%d%d%d%d", &k, &sy, &sx, &ey, &ex); 85 --sx, --sy, --ex, --ey; 86 BFS(); 87 } 88 return 0; 89 }