HDU 5335 Walk Out (BFS后贪心)

来源:互联网 发布:莱州网络销售招聘 编辑:程序博客网 时间:2024/05/23 02:05

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5335

题意:给出一个n*m的地图,你要从最左上角的格子走到最右下角的格子,每个格子上有0或1,没到一个格子你要按顺序记下上面的数字,最后得到一个01串,这个01串是一个二进制数,请输出你能得到的最小的二进制数,不要前导0除非答案为0。

思路:首先希望得到的二进制数尽量短。比如一个 3 * 4 的地图,第一个 1 出现的位置与二进制数长度的最小值的关系如下:

6 5 4 3

5 4 3 2

4 3 2 1

我们要使第一个 1 出现在标号小的位置,然后只向下或向右走,否则会增加二进制数的长度。

选择下一步时,我们又希望离最后一步越远的位置越要是0,即每一步优先选0。

把图像上面那样分层,每一步都会走到标号更小的一层。

代码:

#include <stdio.h>#include <string.h>#include <queue>using namespace std;char a[1005][1005];int can[1005][1005], ans[3000], vis[1005][1005];int dx[6]=  {1, -1, 0, 0};int dy[6] = {0, 0, -1, 1};int str, n, m;struct P{    int x, y;}cur, nex;int ok(int x, int y){    if(!vis[x][y] && x >= 0 && x < n && y >= 0 && y < m)        return 1;    else return 0;}void bfs(int x, int y){    if(a[x][y] == '1')    {       return;    }    cur.x = x; cur.y = y;    queue<P> que;    que.push(cur);    vis[x][y] = 1;    while(!que.empty())    {        cur = que.front();        can[cur.x][cur.y] = 1;        que.pop();        for(int i = 0; i < 4; i++)        {            nex.x = cur.x + dx[i];            nex.y = cur.y + dy[i];            if(ok(nex.x, nex.y))            {                if(a[nex.x][nex.y] == '0')                {                    que.push(nex);                    vis[nex.x][nex.y] = 1;                    if(nex.x + nex.y > str)                    {                        str = nex.x + nex.y;                    }                }            }        }    }}int main(){    int t;    scanf("%d ", &t);    while(t--)    {        scanf("%d %d ", &n, &m);        for(int i = 0; i < n; i++)        {            scanf("%s", a[i]);        }        memset(vis, 0, sizeof(vis));        memset(can, 0, sizeof(can)); //can[i][j] = 1则在第 i + j层时走到i,j这个格子能得到最优解        str = 0;        bfs(0,0); //str记录从起点能走到的0,离终点最近是在哪一层        str++; //则使二进制数最短的第一个1出现在下一层        //printf("str=%d\n", str);        int cnt = 0;        ans[cnt++] = a[0][0] - '0';        //printf("%d\n", ans[0]);        can[0][0] = 1;        for(int f = str; f < n + m - 1; f++)        {            int i, j, flag = 0;            if(f < n)            { //左上部分的层                i = f; j = 0;            }            else            { //右下部分的层                i = n - 1, j = f - n + 1;            }            while(i >= 0 && j < m)            {                if(a[i][j] == '0')                { //优先找0                    if((i - 1 >= 0 && can[i - 1][j]) ||(j - 1 >= 0 && can[i][j - 1]))                    { //这一格可以由 能求得最优答案 的格子走来                        flag = 1;                        can[i][j] = 1;                    }                }                //printf("i-%d,j=%d\n", i, j);                i--; j++;            }            if(flag)            { //找到0                ans[cnt++] = 0;                //printf("f=%d,%d\n", f, ans[cnt - 1]);                continue;            } //找不到0,找1            if(f < n)            {                i = f; j = 0;            }            else            {                i = n - 1, j = f - n + 1;            }            while(i >= 0 && j < m)            {                if(a[i][j] == '1')                {                    if((i - 1 >= 0 && can[i - 1][j]) ||(j - 1 >= 0 && can[i][j - 1]))                    {                        can[i][j] = 1;                    }                }                //printf("i-%d,j=%d\n", i, j);                i--; j++;            }            ans[cnt++] = 1;            //printf("f=%d,%d\n", f, ans[cnt - 1]);        }        int flag = 0;        for(int i = 0; i < cnt; i++)        {            if(ans[i] == 0 && flag)            {                printf("0");            }            else if(ans[i] == 1)            {                printf("1");                flag = 1;            }        }        if(!flag)            printf("0\n");        else printf("\n");    }    return 0;}


0 0
原创粉丝点击