很有意思,很好的题目。
这样的,一个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 ",++cas); else printf("Case #%d: Fanglaoshi ",++cas); } return 0; }