HDOJ 5335 Walk Out 【bfs 贪心 斜行dp】

3 篇文章 0 订阅
3 篇文章 0 订阅

HDOJ 5335 Walk Out 【bfs 贪心 斜行dp】

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


题目就是在一个只有0 1 的矩阵里从左上角走到右下角
每走一步记录当前的坐标值 输出所有结果中数值最小的结果 输出时去掉前缀零。
很明显如果有全部是0的部分,直接输出0就可以了
前面不管有多少个0都是可以去掉的
从1开始之后,数字的长度就固定了
而长的数总比短的数大
所以先bfs只走0走到最深处
之后贪心,如果下一步可以走0就走0,走到最后输出即可


实现的细节是如果开始是1的话就可以不必进入bfs
以及bfs如果可以到达右下角的出口就可以直接输出0
(注意只有一个数据的情况,如果是0。。。)
其他的情况先将最右下角可以到达的0都标记成可以达到
之后按照层数(layer = i+j) 依次递增找到周围可达的下一个点(只走右边或者下边)如果有0就改变标记,之后只走符合标程的下一个位置即可。


每一层的结点其实找起来也比较恶心……
代码最后有一些样例……送给泥萌……不谢……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define clr(c, x) memset(c, x, sizeof(c));
const int INF = 0x3f3f3f3f;
typedef struct point{
    int x, y;
    bool operator < (const point& p) const{
        if(x == p.x) return y < p.y; // 先按照行比较大小,行相同按照列比较大小
        else return x < p.x;
    }
    bool operator > (const point& p) const { return p < *this; }
}p;
int dirx[4] = {0, 1, 0, -1};
int diry[4] = {1, 0, -1, 0};
const int MAXL = 1005;
char maze[MAXL][MAXL];
int T, n, m;
int step[MAXL][MAXL]; // bfs
queue<p> q;
p start, goal, startDfs;
int x, y, xx, yy; // x,y current; xx,yy next;
int stepDfs;
char ans[MAXL*MAXL+1];
bool unlock[MAXL][MAXL];
bool subflag;
int layer;

bool Inside(int xx, int yy){ // 越界判断
    if(xx >= 0 && xx < n && yy >= 0 && yy < m) return true;
    else return false;
}

void bfs(){ // 连续走0
    layer = 0;
    start.x = 0, start.y = 0;
    p current, next;
    clr(step, 0);
    while(!q.empty()) q.pop();
    subflag = true;
    step[0][0] = 1;
    if(maze[0][0] == '1'){
            subflag = false;
            return; // 起点就为1时就不必bfs了
    }
    q.push(start);

    while(!q.empty()){
        current = q.front();
        x = current.x, y = current.y;
        layer = layer > (x+y) ? layer : (x+y);
        for(int i = 0; i < 4; i++){
            xx = x + dirx[i], yy = y + diry[i];
            if(Inside(xx, yy) && maze[xx][yy] == '0' && step[xx][yy] == false){
                next.x = xx, next.y = yy;
                step[xx][yy] = step[x][y] + 1;
                q.push(next);
            }
        }
        q.pop();
    }
    return;
}

void Result(){
    p current, next;
    clr(ans, '1');
    clr(unlock, 0);
    if(layer == n-1+m-1 && maze[0][0] == '0'){ // 如果有一条路可以走到终点且全为0
        puts("0"); // 只输出一个0
        return;
    }
    int X, Y;
    for(X = 0; X < n; X++){
        if(layer-X >= 0 && layer-X < m){
            Y= layer - X;
            if(step[X][Y] != 0){
                unlock[X][Y] = true;
                ans[layer] = maze[X][Y];
            }
        }
    }
    int layerSave = layer;
    int ansLeft = n-1 + m-1 - layer;
    while(ansLeft--){
        for(X = 0; X < n; X++){
            if(layer-X >= 0 && layer-X < m){
                Y= layer - X;
                if(unlock[X][Y] == true){ // 找到下一层可以走的符号
                    if(X+1 <= n-1) ans[layer+1] = ans[layer+1] < maze[X+1][Y] ? ans[layer+1] : maze[X+1][Y];
                    if(Y+1 <= m-1) ans[layer+1] = ans[layer+1] < maze[X][Y+1] ? ans[layer+1] : maze[X][Y+1];
                }
            }
        }
        for(X = 0; X < n; X++){
            if(layer-X >= 0 && layer-X < m){
                Y= layer - X;
                if(unlock[X][Y] == true){
                    if(maze[X+1][Y] == ans[layer+1] && X+1 <= n-1) unlock[X+1][Y] = true;
                    if(maze[X][Y+1] == ans[layer+1] && Y+1 <= m-1) unlock[X][Y+1] = true;
                }
            }
        }
        layer++;
    }
    if(subflag) for(int i = layerSave + 1; i <= n-1+m-1; i++) printf("%c", ans[i]);
    else for(int i = 0; i <= n-1+m-1; i++) printf("%c", ans[i]);
    printf("\n");
}

int main(){
    scanf("%d", &T);
    while(T--){
        clr(maze, 0);
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++) scanf("%s", maze[i]);
        bfs();
        Result();
    }
    return 0;
}

/*
10
1 1
1
1 1
0
1 5
00101
5 1
0
0
1
0
1
2 2
11
11
3 3
001
111
101
5 5
11101
00100
01000
01011
11111
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值