X-man

导航

hdu 4678 Mine

HDU 4678

      把点开空地时会打开的一大片区域看成一块,题目中说到,在一盘游戏

中,一个格子不可能被翻开两次,说明任意两块空地不会包含相同的格子。

那么就可以看成一个组合游戏。

当空地旁边没连任何数字的时候,sg = 1(直接转移到 0)。如果有一个

数字,点空地可以转移到 0,点数字可以转移到 1,所以 sg = 2。有 2 个数

字点空地转移到 0,点数字转移到 2,所以 sg = 1。

以此类推,空地旁边有奇数个数字的时候,sg = 2,否则 sg = 1。

剩下的没与空地相连的数字,每个的 sg 都是 1。

那么将所有空地的 sg 异或起来,再异或 (不与空地相连的数字个数对 2

取模),等于零输出后手赢,大于 0 输出先手赢即可。

#include<stdio.h>
#include<string.h>
#pragma comment(linker,"/STACk:1024000000,1024000000")
int map[1100][1100];
//bool flag[1100][1100];
int f[8][2]= {{0,1},{0,-1},{-1,1},{-1,0},{-1,-1},{1,-1},{1,0},{1,1}};
int n,m;
int tmp;
int dfs(int i,int j)
{
    map[i][j]=3;
    for(int k=0; k<8; k++)
    {
        int x=i+f[k][0];
        int y=j+f[k][1];
        if(x>=0&&y>=0&&x<m&&y<n)
        {
            if(map[x][y]==1)
            {
                map[x][y]=2;
                tmp++;
            }
            else if(!map[x][y])dfs(x,y);
        }
    }
    return 0;
}
void myprintf()
{
    for(int i=0;i<m;i++)
    {

         for(int j=0;j<n;j++)
    printf("%d ",map[i][j]);
    printf("\n");
    }

}
int main()
{
    int _case,ij;
    int ki,i,j,xi,yi;
    scanf("%d",&_case);
    for(ij=1; ij<=_case; ij++)
    {
        memset(map,0,sizeof(map));
        int ans=0;
        scanf("%d%d%d",&m,&n,&ki);
        for(i=0; i<ki; i++)
        {
            scanf("%d%d",&xi,&yi);
            map[xi][yi]=3;
            for(int k=0; k<8; k++)
            {
                int x=xi+f[k][0];
                int y=yi+f[k][1];
                if(x>=0&&y>=0&&x<m&&y<n)
                {
                    if(!map[x][y])map[x][y]=1;
                }
            }
        }
        for(i=0;i<m;i++)
        {
            for(j=0;j<n;j++)
            if(!map[i][j])
            {
                tmp=0;

                dfs(i,j);
                //printf("##%d\n",tmp);
                if(tmp&1)ans^=2;
                else ans^=1;
            }
        }

        int ans1=0;
        //int ans2=0;
        //myprintf();
        for(i=0;i<m;i++)
        {
            for(j=0;j<n;j++)
            {
                if(map[i][j]==1)ans1++;
            }
        }
        ans1%=2;
        ans^=ans1;
        printf("Case #%d: ",ij);
        if(ans)printf("Xiemao\n");
        else printf("Fanglaoshi\n");
    }
    return 0;
}

 

/* 
//求sg函数值代码如下 
#include <stdio.h> 
#include <string.h> 
#include <algorithm> 
#include <iostream> 
using namespace std; 
#define maxn 1111 
int sg[maxn];//sg[i]表示由一个空白区域加上i-1个边缘数字区的sg值 
int vis[maxn]; 
void init() 
{ 
    int i,j,k; 
    sg[0]=0; 
    sg[1]=1; 
    for(i=2;i<1000;i++) 
    { 
        memset(vis,0,sizeof(vis)); 
        vis[sg[i-1]]=1;  //点击数字区域 
        vis[0]=1;       //点击空白区域,后继状态必败 
        for(j=0;;j++) 
        if(vis[j]==0) 
        { 
            sg[i]=j; 
            break; 
        } 
    } 
    for(i=0;i<20;i++) 
    cout<<sg[i]<<" "; 
    cout<<endl; 
} 
int main() 
{ 
    init(); 
    return 0; 
} 
//SG值:0 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 
*/  
View Code

 

posted on 2013-08-17 14:38  雨钝风轻  阅读(267)  评论(0编辑  收藏  举报