HDU 1536 S-Nim (博弈 sg函数 Nim和)

来源:互联网 发布:阿里云搭建svn 编辑:程序博客网 时间:2024/05/22 03:31

原题网址:

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;}
0 0