题意:
一个棋盘有n行,每行20格子,都有一些棋子,两个人轮流进行这个操作:选择某一行一个棋子移动到该行右边第一个空的格子。不能进行的人输。问先手是否能赢。
分析:
SG函数的应用,当时自己做的时候没做出来QAQ。终结点是这一行没有棋子可以走,即0,然后逆推出其他结点的SG函数。每一行的状态看成是一个结点,然后把状态二进制压缩,1表示有棋子,0表示空格。
#include<cstdio>
#include<cstring>
using namespace std;
int sg[1<<21],vis[21];
int getSG(int x)
{
memset(vis,0,sizeof(vis));
for(int i=20;i>=0;i--){
if(x&(1<<i)){
int t=x;
for(int j=i-1;j>=0;j--)if(!(x&(1<<j))){
t^=(1<<i)^(1<<j);
vis[sg[t]]=1;break;
}
}
}
for(int i=0;i<=20;i++)if(!vis[i])return i;
}
int main()
{
memset(sg,0,sizeof(sg));
for(int i=0;i<(1<<20);i++)
sg[i]=getSG(i);
int T;scanf("%d",&T);
while(T--){
int n,m,x,ans=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&m);
int st=0;
while(m--){
scanf("%d",&x);
st|=1<<(20-x); //是从右边开始的,21这个位置为0
}
ans^=sg[st];
}
printf("%s\n",ans?"YES":"NO");
}
return 0;
}
本文介绍了一个基于SG函数的算法,用于解决一个棋盘游戏问题。在这个游戏中,两个玩家轮流移动棋子到同一行的右侧空位,直至无法移动为止。文章详细解析了如何使用SG函数来判断先手玩家是否能够赢得比赛,包括状态压缩和SG函数的计算过程。
2809

被折叠的 条评论
为什么被折叠?



