题目链接:点击打开链接
题意很简单,用俄罗斯方块填充图形,有些格子有障碍物,最后一个放下方块的人取得胜利,懒得介绍了~
考点是博弈论sg函数的用法~~这个题目难点在于是最多能放下10个俄罗斯正方形~50*50的布局使得单纯的状态压缩无法记录已经搜索过的值,但是初始状态能转化到的所有子状态数量又是有限的~所以这里要用到字符串的hash,我这里是直接用的字典树将状态离散化的~~附上代码~~
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN=60;
char chess[MAXN][MAXN];
int n,m;
void print()
{
printf("Debug\n");
for(int i=0;i<n;i++)
puts(chess[i]);
}
struct hashCode
{
const static int SIZE=100000;
struct node_t
{
node_t *son[2];
int idx;
}Node[SIZE];
int toUsed;
inline void init()
{
toUsed=1;
memset(Node,0,sizeof(node_t));
}
inline node_t* _NewNode()
{
memset(Node+toUsed,0,sizeof(node_t));
return Node+toUsed++;
}
inline void insert(const char word[],int data)
{
node_t *loc=Node;
for(int i=0;word[i];i++)
{
int sn=word[i]-'0';
if(!loc->son[sn]) loc->son[sn]=_NewNode();
loc=loc->son[sn];
}
loc->idx=data;
}
inline int find(const char word[])
{
node_t *loc=Node;
for(int i=0;word[i];i++)
{
int sn=word[i]-'0';
if(!loc->son[sn]) return -1;
loc=loc->son[sn];
}
return loc->idx;
}
};
hashCode dp;
inline void to_status(char str[])
{
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
str[i*m+j]=chess[i][j];
str[n*m]='\0';
}
int dfs()
{
char str[MAXN*MAXN];
to_status(str);
int ret=dp.find(str);
if(ret!=-1) return ret;
bool sg[150];
memset(sg,false,sizeof(sg));
for(int i=0;i<n-1;i++)
for(int j=0;j<m-1;j++)
if(chess[i][j]=='0'&&chess[i][j+1]=='0'&&chess[i+1][j]=='0'&&chess[i+1][j+1]=='0')
{
chess[i][j]=chess[i][j+1]=chess[i+1][j]=chess[i+1][j+1]='1';
int sign=dfs();
sg[sign]=true;
chess[i][j]=chess[i][j+1]=chess[i+1][j]=chess[i+1][j+1]='0';
}
while(true)
{
if(!sg[++ret])
{
dp.insert(str,ret);
return ret;
}
}
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
dp.init();
int sign=0;
for(int i=0;i<t;i++)
{
scanf("%d%d",&n,&m);
for(int j=0;j<n;j++)
scanf("%s",chess[j]);
sign^=dfs();
}
puts(sign?"Yes":"No");
}
return 0;
}