poj2157 BFS

/**
 * poj2157 BFS
 * 这个题,我只能说是非常的烦,烦爆了,但也没有什么办法。因为BFS是肯定的,但是细节的东西真的很难把握,不知道哪里错就WA了
 * 我第一次自己做的,WA了无数次,后来还是放弃了,转用别人的思路重做了一遍,终于才AC
 * 这个思路就是遇到不能打开的门,先把这些门的坐标记下来,等你搜了一遍以后,以这些门的坐标作为起点,重新刷一遍bfs,因为之前已经刷过的点就不用重刷了,所以child=-1也是可以接受的
 * 因为最差的结果就是你每次都找到了新的钥匙可以打开新的门,但这样的次数也不会超过5次,所以checkcount<5就可以了,如果你真的需要门开了拿到别的门的钥匙,那就肯定要过5遍的啦
 * 反正这个题你怎么做都是0ms,放心大胆去试就行了,细节,细节...
 */
#include <cstdio>
#include <cstring>
const int MAX_NUM = 25;

int m,n;
int xstart,ystart;
char map[MAX_NUM][MAX_NUM];
int keynum[5];
bool vis[MAX_NUM][MAX_NUM];
char dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
struct point{
    int x;
    int y;
} p[MAX_NUM*MAX_NUM],door[5];

bool bfs(int xs,int ys){
    int father = -1,child = 0;
    memset(vis,0,sizeof(vis));
    vis[xs][ys] = true;
    p[0].x = xs;
    p[0].y = ys;

    int doornum=0,checkcount=0;
    while(checkcount < 5){
        if(father == child){
            father = -1;
            child = -1;
            for(int i=0;i<doornum;++i){
                if(keynum[map[door[i].x][door[i].y] - 'A'] == 0){
                    child++;
                    p[child].x = door[i].x;
                    p[child].y = door[i].y;
                }
            }
            checkcount++;
        }

        if(father == child) break;
        ++father;
        int x,y;
        for(int i=0;i<4;++i){
            x=p[father].x+dir[i][0];
            y=p[father].y+dir[i][1];
            if(x>=0 && x<m && y>=0 && y<n && !vis[x][y] && map[x][y]!='X'){
                if(map[x][y] == 'G'){
                    return true;
                }
                else if(map[x][y] == '.'){
                    vis[x][y] = true;
                    child++;
                    p[child].x = x;
                    p[child].y = y;
                    
                }
                else if(map[x][y] >= 'A' && map[x][y] <= 'Z'){
                    vis[x][y] = true;
                    if(keynum[map[x][y]-'A'] == 0){
                        child++;
                        p[child].x = x;
                        p[child].y = y;
                    }
                    else{
                        door[doornum].x = x;
                        door[doornum].y = y;
                        doornum++;
                    }
                }
                else if(map[x][y] >= 'a' && map[x][y] <= 'z'){
                    --keynum[map[x][y] - 'a'];
                    vis[x][y] = true;
                    child++;
                    p[child].x = x;
                    p[child].y = y;
                }
            }
        }
    }
    return false;
}


int main(){
    while(scanf("%d%d",&m,&n)!=EOF){
        if(m==0&&n==0){
            break;
        }
        memset(keynum,0,sizeof(keynum));

        for(int i=0;i<m;++i){
            scanf("%s",map[i]);
            for(int j=0;j<n;++j){
                if(map[i][j] == 'S'){
                    xstart = i;
                    ystart = j;
                    map[i][j] = '.';
                }
                else if(map[i][j] >= 'a' && map[i][j] <= 'e'){
                    keynum[map[i][j]-'a']++;
                }
            }
        }

        if(bfs(xstart,ystart)) puts("YES");
        else puts("NO");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值