很有意思,很好的题目。
这样的,一个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; }