HDU4678_Mine

很有意思,很好的题目。

这样的,一个n*m的扫雷地图,告诉你哪些地方是有雷的。一个人如果点在了空白处,那么与其相邻的(八个方向)的数字以及空白都会递归地显示出来,如果点在数字上面,那么就只会显示这一个数字。

游戏过程中,谁第一个无法点开一个非雷的格子算输。

这、、、、其实可以看成是nim博弈问题,但是有一点点点点的不同。

我们由于题目说明了数字的部分不会有重复的,所以我们把一个由空白部分连成的区域看成是一堆石子,那么有的单独的数字就是一堆石子且只有一颗。

同时我们把所有的空白区域看成是一个石子,这样问题就转化为了给你N堆石子,以及每一堆的石子的数量,现在要你求出博弈的结果是先手胜还是后手胜?

由于每次可选择的可以使一堆中的某一颗石子,也可以是一整堆的石子,所以这与单纯的nim博弈是有所区别的。

其实可以这样来考虑这个问题。

我们分别统计出石子数量为奇数的堆有多少个(x)、石子数为偶数的堆有多少个(y)。

那么其实,除非x和y均为偶数,否则先手必胜。

这样来理解,其实博弈过程中,必胜者只要一直维护所有的石子数之和为偶数即可。

但是如果是一开始就为偶数偶数的话,那么就是必输了。

不知道这么理解对不对呢?

 

 

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1010
using namespace std;

int a[maxn][maxn],t,n,m,k,xi,yi,ans,cas=0,tot,flag;
bool b[maxn][maxn],vis[maxn][maxn];

int dfs(int x,int y)
{
    if (a[x][y]==-1 || x<1 || x>n || y<1 || y>m) return 0;
    if (b[x][y]) return 0;
    b[x][y]=true;
    if (a[x][y]!=0) return 1;
    return dfs(x+1,y)+dfs(x-1,y)+dfs(x,y+1)+dfs(x,y-1)+dfs(x-1,y-1)+dfs(x-1,y+1)+dfs(x+1,y-1)+dfs(x+1,y+1);
}

int main()
{
    scanf("%d",&t);
    while (t--)
    {
        memset(a,0,sizeof a);
        memset(b,false,sizeof b);
        memset(vis,false,sizeof vis);
        scanf("%d%d%d",&n,&m,&k);
        tot=0;
        while (k--)
        {
            scanf("%d%d",&xi,&yi);
            xi+=1,yi+=1;
            vis[xi][yi]=true;
        }
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++)
            {
                if (vis[i][j])
                {
                    a[i][j]=-1;
                    continue;
                }
                a[i][j]=0;
                for (int ii=-1; ii<=1; ii++)
                    for (int jj=-1; jj<=1; jj++)
                        if (vis[i+ii][j+jj]) a[i][j]++;
            }
        ans=0;
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++)
            {
                if (b[i][j]) continue;
                if (a[i][j]==0)
                {
                    int tep=dfs(i,j)+1;
                    if (tep&1) ans^=1;
                        else ans^=2;
                    tot++;
                }
            }
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++)
            {
                if (b[i][j]) continue;
                if (a[i][j]==-1) continue;
                b[i][j]=true;
                ans^=1;
                tot++;
            }
        if (ans) printf("Case #%d: Xiemao\n",++cas);
            else printf("Case #%d: Fanglaoshi\n",++cas);
    }
    return 0;
}

 

posted @ 2013-11-29 19:19  092000  阅读(315)  评论(0编辑  收藏  举报