原题网址:
http://acm.hdu.edu.cn/showproblem.php?pid=1536
思路:
Nim的变形,只是对你每次选取的数量做了限制,但是其他的性质并没有改变,所以可以用sg函数解决;
又或者说,Nim游戏只是一种特例,事实上有多种问题都可以用sg函数解决。
sg函数的定义:
sg(x) = mex { sg(y) | x->y } //mex (minimal excludant)
x->y 表示从x转移到y,mex(Y)表示的是不存在于集合中的最小自然数。例如mex(0,1,2,5,8,9) = 3,mex(1,2,5) = 0
在Nim游戏中可以用sg函数进行分析
(1)一堆石子的情况:
sg(0) = 0,sg(1) =mex{ sg(0)} = 1,sg(2) = mex(sg(0),sg(1)) = 2;。。。
然后总的来说,对于单堆的这种情况,sg(x) = x
(2)多堆石子的情况:
sg(a,b……) = a ^ b ^…… 即 a堆的sg函数值与b堆等的sg函数值的异或。
最后如果是0,说明先手必败,否则先手必胜。
证明:
我不会。
附上我之前看的别人的网址:
http://www.cnblogs.com/exponent/articles/2141477.html
http://www.physixfan.com/archives/563
我觉得这两篇讲的很好,让我对Nim和,sg函数的理解更深了。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
using namespace std;
int s[120];
int sn;
int mem[10010];
int sg(int n){
if(mem[n] != -1)return mem[n];
if(n < s[0]) return 0;
int hash_[102];
memset(hash_,-1,sizeof(hash_));
int i = 0;
for(;n >= s[i] && i < sn;i++){
hash_[sg(n-s[i])]++;
}
for(int j = 0;j < 101;j++){
if(hash_[j] == -1)
return mem[n] = j;
}
return -200000000;// 这句没啥意思,按照正常的规则走的话根本不会走到这一步。
}
int main()
{
int ncase;
int ans;
while(scanf("%d",&sn),sn){
memset(mem,-1,sizeof(mem));
for(int i = 0;i < sn;i++){
scanf("%d",s+i);
}
sort(s,s+sn);
scanf("%d",&ncase);
int n;
int temp;
for(int i = 1;i <= ncase;i++){
scanf("%d",&n);
scanf("%d",&temp);
ans = sg(temp);
for(int j = 0;j < n-1;j++){
scanf("%d",&temp);
ans ^= sg(temp);
}
if(ans != 0)
printf("W");
else
printf("L");
}
printf("\n");
}
return 0;
}