HDU4678Mine(博弈+sg)

来源:互联网 发布:沈宏非的淘宝店 编辑:程序博客网 时间:2024/05/29 17:50

题目链接:传送门 

题意:

一个扫雷的游戏,告诉你雷的位置,然后可以根据雷的位置建立出一个图,一个位置上的数字代表他相邻的八个方向上一共有多少个雷,没有数字的代表周围没有雷。两个人玩游戏,每次可以选一个位置来翻转,如果上面有数字的话,那么就只能翻转这一个,如果是空白的话可以把他附近的空白的以及空白的附近挨着的数字的全部翻转。,谁不能翻转了则谁输。问在两方都使用最优策略的情况下谁会赢。

分析:

我们可以首先把这些空白的相邻的区域都给Bfs出来,看成一堆一堆的石头,每次只能取一个或者全部取光,然后根据SG定理可以求出SG值,最后发现 SG(x) = 2 - x%2;然后全部异或起来,注意还要把所有数字的没有翻转的进行异或。

代码如下:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <queue>using namespace std;const int maxn = 1e3+10;const int dx[]={0,0,-1,-1,-1,1,1,1};const int dy[]={-1,1,0,-1,1,0,1,-1};int mp[maxn][maxn];bool vis[maxn][maxn];int n,m,k;bool check(int x,int y){    if(x<0||x>=n||y<0||y>=m||mp[x][y]==-1) return false;    return true;}typedef pair<int ,int > PII;int BFS(int x,int y){    queue<PII>Q;    Q.push(make_pair(x,y));    vis[x][y]=1;    int num=1;    while(!Q.empty()){        PII top = Q.front();        Q.pop();        for(int i=0;i<8;i++){            int tmpx = top.first+dx[i];            int tmpy = top.second+dy[i];            if(!check(tmpx,tmpy)||vis[tmpx][tmpy]) continue;            if(mp[tmpx][tmpy]>0) num++;            if(mp[tmpx][tmpy]==0) Q.push(make_pair(tmpx,tmpy));            vis[tmpx][tmpy]=1;        }    }    //cout<<"num "<<num<<endl;    return num;}int main(){    int t,cas=1;    scanf("%d",&t);    while(t--){        scanf("%d%d%d",&n,&m,&k);        memset(vis,0,sizeof(vis));        memset(mp,0,sizeof(mp));        for(int i=0;i<k;i++){            int x,y;            scanf("%d%d",&x,&y);            mp[x][y]=-1;            for(int j=0;j<8;j++){                int tmpx=x+dx[j];                int tmpy=y+dy[j];                if(check(tmpx,tmpy)) mp[tmpx][tmpy]=1;            }        }//        for(int i=0;i<n;i++){//            for(int j=0;j<m;j++)//                cout<<mp[i][j]<<" ";//            cout<<endl;//        }        int ans = 0;        for(int i=0;i<n;i++){            for(int j=0;j<m;j++){                if(mp[i][j]==0&&!vis[i][j])                    ans^=2-BFS(i,j)%2;            }        }        for(int i=0;i<n;i++){            for(int j=0;j<m;j++)                if(mp[i][j]==1&&!vis[i][j])                    ans^=1;        }        printf("Case #%d: ",cas++);        if(ans) puts("Xiemao");        else puts("Fanglaoshi");    }    return 0;}/***33 3 03 3 11 14 4 21 11 2***/

 

0 0