题目链接:poj 2960
这道题算是我博弈论的入门吧= =。。。
首先了解SG值吧。对于sg值我们需要掌握:1.当前局面的sg[x]=mex{sg[y]},其中y为到达x局面的上一个局面,mex函数的值为最小的不属于该集合的非负整数。 2.对于有多个局面的有向游戏的和局面的sg值为各个局面sg值的异或值。
到现在,我也就掌握了这么多,要了解其他具体的知识,可以找度娘。
然后来看看这道题吧。我们惊奇的发现其实就是暴力求出各个局面的sg值,再取异或值即可。若异或值为0,则先手输,否则先手赢。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int K,M,L;
int s[110],sg[10000+10];
int get(int x){//求x的sg值
if(sg[x]!=-1)return sg[x];//记忆化
bool vis[10000+10];
memset(vis,0,sizeof(vis));//memset效率低下,数组改为bool型大大优化时间
for(int i=1;i<=K;i++){
int y=x-s[i];
if(y>=0){
int cmp=get(y);
vis[cmp]=1;
}
}
for(int i=0;;i++)
if(!vis[i])return sg[x]=i;
}
int main(){
while(scanf("%d",&K)==1){
if(K==0)break;
for(int i=1;i<=K;i++)scanf("%d",&s[i]);
memset(sg,-1,sizeof(sg));
sg[0]=0;
scanf("%d",&M);
while(M--){
scanf("%d",&L);
int x,ans=0;
while(L--){//整个游戏的sg值为各个游戏局面sg值的异或值
scanf("%d",&x);
ans^=get(x);
}
if(ans)printf("W");
else printf("L");
}
printf("\n");
}
return 0;
}