其实这道题不用费很大的功夫去找平衡态,我们只需要回到sg函数定义上面来.
sg函数的定义:
首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
对于一个给定的有向无环图,定义关于图的每个顶点的SG函数如下:sg(x)=mex{ sg(y) | y是x的后继 },即一个节点的sg函数值等于其所有后继结点的sg函数值集合的mex。
所以,对于这道题,对于每一个状态,我们都可以将它的所有子状态找出来,然后通过其子状态的sg值,求出此点的sg值.将所有点sg值求出,就是一个nim博弈问题了.
对于两个炸弹在一起会爆炸这个问题,不需要特殊考虑,因为如果两个炸弹在一起,即使不爆炸,他们合起来的sg值也会为0,
所有爆不爆炸对必胜必败态并无影响.
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int g_sg[60][60];
char map[60][60];
int g_tmp[600];
int calSg(int x,int y)
{
memset(g_tmp,-1,sizeof g_tmp);
int i,j;
for(i=0;i<x;i++)
{
for(j=0;j<y;j++)
{
g_tmp[g_sg[i][y]^g_sg[x][j]]=1;
}
}
for(i=0;i<500;i++)
if(g_tmp[i]==-1)
{
return g_sg[x][y]=i;
}
}
int main()
{
int i,j,a,k;
int n,s,m;
for(i=0;i<=50;i++)
g_sg[0][i]=i,g_sg[i][0]=i;
for(i=1;i<=50;i++)
{
for(j=1;j<=50;j++)
calSg(i,j);
}
while(2==scanf("%d%d",&n,&m)&&n)
{
s=0;
for(i=0;i<n;i++)
{
scanf("%s",map[i]);
for(j=0;j<m;j++)
{
if(map[i][j]=='#')
s^=g_sg[i][j];
}
}
if(s) puts("John");
else puts("Jack");
}
}