Walk Out
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)2 2 2 11 11 3 3 001 111 101
111 101
给出一个由0和1组成的地图,求从左上角到右下角走过的路程中01的值组成的二进制所表示的值最小
找出使二进制长度最短的点, 从该点(可能有多个)开始以后每一步只可往右/下方向走,因为此时任何一个往左/上的操作都将是二进制长度增加,从而值增大
算法过程:
第一步:
(1)当开头为0 时,需考虑前导0问题,bfs找出离左上角曼哈顿距离最远的点,则该点距右下角出口最近,所组成的二进制长度最短(点可能有多个,都加进求解队列a),此时有可能找到出口,则直接输出出口字符结束即可
(2)当开头为1时,直接把入口加入结果队列
第二步:
(1)对于当前求解队列a中的所有点(x, y) ,若存在0,则把0加入结果队列,并把此点可达点(x+1, y) 和(x, y+1)加入另一个求解队列b,若不存在0,则把所有队列中所有点的可达点(x+1, y)和(x, y+1)加入求解队列b,直到找到出口算法结束
(2)交换a,b队列,继续(1)
#include <stdio.h> #include <string.h> char mp[1005][1005]; int T, n, m, ch, cnt, q[2][3000500], g = 0, c[2], mn; char re[2010], v[1005][1005]; void f(){ int mx = m + n + 1 - mn; //需要查找的位数 for (int i = 1; i <= mx; ++i){ char fg = 1; //当前求解队列a中是否存在0的标记 int tg = !g; //求解队列b的标记 c[tg] = -1; //求解队列b的长度 while (c[g] > 0){ int y = q[g][c[g]--]; int x = q[g][c[g]--]; if (x > n || y > m) continue; if (fg){ if (!v[x+1][y]){ q[tg][++c[tg]] = x+1; q[tg][++c[tg]] = y; v[x+1][y] = -1; //注意此处赋值-1是为了避免当求解队列a存在0时导致的可达点遗漏问题 } if (!v[x][y+1]){ q[tg][++c[tg]] = x; q[tg][++c[tg]] = y+1; v[x][y+1] = -1; } } if ('0' == mp[x][y]){ if (fg) c[tg] = -1; //第一次找到0,求解队列b清空 if (0 >= v[x+1][y]){ //未访问则加入 q[tg][++c[tg]] = x+1; q[tg][++c[tg]] = y; v[x+1][y] = 1; } if (0 >= v[x][y+1]){ q[tg][++c[tg]] = x; q[tg][++c[tg]] = y+1; v[x+1][y] = 1; } fg = 0; } } re[++cnt] = fg; g = !g; } } void bfs(){ memset(v, 0, sizeof(v)); cnt = -1; c[g] = -1; //当前广搜队列标志 int tg = !g; //最远点队列标志 q[g][++c[g]] = 1; //入口加入广搜队列 q[g][++c[g]] = 1; mn = 2; if ('0' == mp[1][1]){ //入口为0是bfs寻找最远点 int dir[][2] = {1, 0, -1, 0, 0, 1, 0, -1}; while (c[g] > 0){ int y = q[g][c[g]--]; int x = q[g][c[g]--]; if (x > 0 && y > 0 && x <= n && y <= m){ if (x == n && y == m){ re[++cnt] = mp[x][y] - '0'; return; } if (x + y > mn){ //找到更大值,更新最远点队列 mn = x + y; c[tg] = -1; q[tg][++c[tg]] = x; q[tg][++c[tg]] = y; }else if (x + y == mn){ //找到相同最大值,加入最远点队列 q[tg][++c[tg]] = x; q[tg][++c[tg]] = y; } for (int i = 0; i < 4; ++i){ //bfs if ('0' == mp[x + dir[i][0]][y + dir[i][1]] && !v[x + dir[i][0]][y + dir[i][1]]){ q[g][++c[g]] = x + dir[i][0]; q[g][++c[g]] = y + dir[i][1]; v[x + dir[i][0]][y + dir[i][1]] = 1; } } } } g = !g; //把最远点队列变成求解队列a交给f()使用 } f(); } int main() { scanf("%d", &T); char s[3010]; while (T--){ scanf("%d%d", &n, &m); gets(mp[0]); for (int i = 1; i <= n; ++i){ gets(mp[i] + 1); } bfs(); int i = 0; while (i < m + n && !re[i]) ++i; //除去前导0 if (i > cnt) printf("0"); while (i <= cnt) printf("%d", re[i++]); printf("\n"); } return 0; }