【POJ】5335 - Walk Out 【BFS + 贪心】

题目

Walk Out

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3035    Accepted Submission(s): 620


Problem Description
In an  nm  maze, the right-bottom corner is the exit (position  (n,m)  is the exit). In every position of this maze, there is either a  0  or a  1  written on it.

An explorer gets lost in this grid. His position now is  (1,1) , and he wants to go to the exit. Since to arrive at the exit is easy for him, he wants to do something more difficult. At first, he'll write down the number on position  (1,1) . Every time, he could make a move to one adjacent position (two positions are adjacent if and only if they share an edge). While walking, he will write down the number on the position he's on to the end of his number. When finished, he will get a binary number. Please determine the minimum value of this number in binary system.
 

Input
The first line of the input is a single integer  T (T=10) , indicating the number of testcases. 

For each testcase, the first line contains two integers  n  and  m (1n,m1000) . The  i -th line of the next  n  lines contains one 01 string of length  m , which represents  i -th row of the maze.
 

Output
For each testcase, print the answer in binary system. Please eliminate all the preceding  0  unless the answer itself is  0  (in this case, print  0  instead).
 

Sample Input
   
   
   
   
2 2 2 11 11 3 3 001 111 101
 

Sample Output
   
   
   
   
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)

AC代码


#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;
}


你可能感兴趣的:(poj,out,bfs,贪心,walk,5335)