转载请注明出处:http://blog.csdn.net/vmurder/article/details/42653601
其实我就是觉得原创的访问量比未授权盗版多有点不爽233。。。
题意:
两人轮流从若干堆石子中某堆取k个石子,
k∈集合S, 就是每次取的数量被限定成某几个数的意思!
然后跟正常Nim一样谁不能操作就输。
题解:
SG函数裸题。
SG函数:
首先需要是有向无环图(拓扑图)
首先确定边界状态,SG值为0,然后暴力拓扑得出其它点的SG值。
SG值为所有子集的SG值中未出现的最小自然数。
SG==0为负。
SG函数满足所有游戏(开始状态)的SG异或起来为0则负,为1则胜。
如果你是跟我一样的蒟蒻,不要想着去证明它是对的,写就行了,否则就是一遍又一遍地颓废放弃浪费时间。
代码(看个差不多就扒代码也行):
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 105 #define M 10100 using namespace std; int S,s[N]; int sg[M]; int SG(int x) { int i; if(sg[x]+1)return sg[x]; bool vis[M<<1]={0}; for(i=1;i<=S;i++) if(s[i]<=x)vis[SG(x-s[i])]=true; for(i=0;vis[i];i++); return sg[x]=i; } int n,m; int main() { // freopen("test.in","r",stdin); int i,k,g; while(scanf("%d",&S),S)// 数据组数A { for(i=1;i<=S;i++)scanf("%d",&s[i]); // sort(s+1,s+S+1); // s : 每次可以取的石子数量集合 memset(sg,-1,sizeof(sg)),sg[0]=0; for(scanf("%d",&g);g--;) // 数据组数B { for(k=0,scanf("%d",&n);n--;) // n堆石子 { scanf("%d",&m); // 该堆石子的个数 k^=SG(m); } if(k)putchar('W'); else putchar('L'); } puts(""); } return 0; }
原文地址:http://blog.csdn.net/vmurder/article/details/42653601