[题解] HDU 4101 Ali and Baba (BFS)

  题意:两人轮流开墙,每人一次只能开一个墙(或者打宝藏),打到宝藏的人胜利。
  分析:算出外面所有能敲的墙的数量,因为没人会傻到帮别人去开墙然后别人直接进去拿宝藏…再判断奇偶性,谁敲掉围绕这宝藏的那一圈墙谁就输了。
  在看到这一道题目时,我再一次(恬不知耻的)觉得:(*@ο@*) 哇~,好水啊!准备直接从-1开始BFS,然后将在内部的所有点的数量记录下来,然后用总点数去减去内部点数再判断奇偶性即可得到答案。
  BUT,WA WA WA使我不得不冷静下来,重新看代码…
  原来是有一种情况没有考虑到。
  For example
  7 7
  1 1 1 1 1 1 1
  1 1 0 -1 0 0 1
  1 0 1 1 1 0 1
  1 0 1 1 1 0 1
  1 0 1 1 1 0 1
  1 0 0 0 0 0 1
  1 1 1 1 1 1 1
  这样的数据,第四行,第四个数据就无法读取到,于是乎,瞬间爆炸
  那么怎么解决呢?——双BFS

  双BFS的思路是这样的,将第一次从-1开始扩展得到的点全部标记(其实就是判重数组吗),然后从外往内BFS一遍,如果搜到的是没有标记过的点,入队,将这个点HP敲完;要是标记过,不入队,将这个点HP敲到剩下1滴。那么,敲掉HP的总数即为判断的依据。
  并且要记得,如果第一遍搜出了图,那么说明宝藏直接和外界相连哦,那么Ali就直接赢了。

  看代码↓↓↓
  

#include <bits/stdc++.h>
using namespace std;
bool flag=0;
int n,m,stx,sty,sum=0,total=0;
int MAP[310][310];
bool pd[310][310];
bool pdc[310][310];
int mo[4][2]={1,0,0,1,-1,0,0,-1};
struct node {
    int x,y;
}st;
queue <node> q;//懒得手写队列 X1
queue <node> p;//懒得手写队列 X2
void input() {
    int i,j;
    for(i=0;i<n;i++) {
        for(j=0;j<m;j++) {
            scanf("%d",&MAP[i][j]);
            if(MAP[i][j]==-1) {
                st.x=i;
                st.y=j;
            }
            else {
                sum+=MAP[i][j];
            }
        }
    }
    return;
}
bool bfs2() {//从外往内
    int nx,ny,i,j;
    while(!p.empty()) {p.pop();}
    for(i=0;i<n;i++) {
        p.push(node{i,-1});
        p.push(node{i,m});
    }
    for(j=0;j<m;j++) {
        p.push(node{-1,j});
        p.push(node{n,j});
    }
    while(!p.empty()) {
        node now=p.front();
        p.pop();
        for(int i=0;i<=3;i++) {
            nx=now.x+mo[i][0];
            ny=now.y+mo[i][1];
            if(nx>=0 && nx<n && ny>=0 && ny<m) {
                if(!pdc[nx][ny]) {
                    pdc[nx][ny]=1;
                    if(pd[nx][ny]) {
                        total+=MAP[nx][ny]-1;
                    }
                    else {
                        total+=MAP[nx][ny];
                        p.push(node{nx,ny});
                    }
                }
            }
        }
    }
    if(total&1) {return 1;}
    return 0;
}
bool bfs1() {//从内往外
    int nx,ny;
    while(!q.empty()) {q.pop();}
    q.push(st);
    pd[st.x][st.y]=1;
    while(!q.empty() && !flag) {
        node now=q.front();
        q.pop();
        for(int i=0;i<=3;i++) {
            nx=now.x+mo[i][0];
            ny=now.y+mo[i][1];
            if(nx>=0 && nx<n && ny>=0 && ny<m) {
                if(pd[nx][ny]) continue;
                if(MAP[nx][ny]==0) {
                    q.push(node{nx,ny});
                    pd[nx][ny]=1;
                }
                else if(MAP[nx][ny]>=1) {
                    pd[nx][ny]=1;
                }
            }
            else {flag=1;break;}
        }
        if(flag) {break;}
    }
    if(flag) {return 1;}//要是搜出去了,直接Ali赢
    bfs2();
}
int main() {
    while(~scanf("%d%d",&n,&m)) {
        memset(MAP,0,sizeof(MAP));
        memset(pd,0,sizeof(pd));
        memset(pdc,0,sizeof(pdc));
        total=0;sum=0;flag=0;
        input();
        if(bfs1()) printf("Ali Win\n");
        else printf("Baba Win\n");
    }
    return 0;
}

                           From:Chlience

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值