题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2873
题意:在一个二维的棋盘上有一些炸弹,每一步可以选择引爆一个炸弹,这些炸弹(x,y)分三种情况:
1、x,y>1 , 那么引爆后会在 (u, y) 和(x, v)位置产生两个新的炸弹, u<x, v<y,u,v自选。
2、x = 1 , y > 1,引爆后仅在(1,v)位置产生一个新的炸弹,v<y,v自选。
3、x>1 , y = 1,和上一条同理。
如果两个炸弹在同一个位置或在(1,1)位置时,它们会自动爆炸。
其实在同一个位置这一条不用管的,想想我们组合游戏计算sg值就是把各个单一游戏的sg值异或起来,两个同位置的sg值一定是一样的,所以异或起来也是0,即不用管。
现在我们考虑把这个游戏拆成仅单点(x,y)有炸弹的单一游戏。
首先我们考虑特殊情况(1,1)处的sg值肯定为0,那么对于(1,i)和(i,1)的sg值就为i-1,因为可以转移到任意的(1,j)和(j,1)(j<i)。
那么就可以把剩下的情况sg值计算出来了。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007
const int maxn = 55;
int sg[maxn][maxn];
void init()
{
bool f[maxn*maxn];
rep(i,1,50) sg[i][1] = i-1;
rep(i,1,50) sg[1][i] = i-1;
rep(i,2,50)
rep(j,2,50)
{
Clean(f,false);
rep(x,1,i-1)//枚举所有可以转移的情况
rep(y,1,j-1)
f[ sg[x][j] ^ sg[i][y] ] = true;
int k = 0;
while( f[k] ) k++;
sg[i][j] = k;
}
}
int main()
{
int n,m;
char c;
init();
while( cin>>n>>m )
{
if ( n + m == 0 ) break;
int ans = 0;
rep(i,1,n)
{
getchar();
rep(j,1,m)
{
c = getchar();
if ( c == '#' )
ans ^= sg[i][j];
}
}
puts( ans ? "John" : "Jack" );
}
return 0;
}