一、HDU 1730 Northcott Game 

游戏在一个n行m列(1 ≤ n ≤ 1000且2 ≤ m ≤ 100)的棋盘上进行,每行有一个黑子(黑方)和一个白子(白方)。执黑的一方先行,每次玩家可以移动己方的任何一枚棋子到同一行的任何一个空格上,当然这过程中不许越过该行的敌方棋子。双方轮流移动,直到某一方无法行动为止,移动最后一步的玩家获胜。Tom总是先下(黑方)。图1是某个初始局面,图二是Tom移动一个棋子后的局面(第一行的黑子左移两步)。 

     

题解:

等效于nim游戏。相当于n堆石子,每堆石子的数量等于每行黑白棋子间有多少个空格。如果全部都没有空格了,那么先走的必败,因为后走的可以贴着先走的棋子走,而对方一定在有限步之内穷途陌路,这时就相当于石子取完了。直观不同于nim的是,这里有可能通过反向移动,相当于增加石子,不过这也不会改变必胜必败态的。因为如果此时该走之人出于必胜态,那么就不必反向移动了,如果是必败态想通过增加石子改变必败态,那么另一方可以走相同的方向和步数来维持自己的必胜态,而耍赖一方的耍赖次数也是有限的。  到此模型就完全等价于nim游戏了。

代码:

int main()
{
    int n,m,i,j,k;
    while (~scanf("%d%d",&n,&m))
    {
        int ans=0;
        for (i=1;i<=n;i++)
        {
            scanf("%d%d",&j,&k);
            ans=ans^(abs(j-k)-1);
        }
        if (ans)puts("I WIN!");else puts("BAD LUCK!");
    }
    return 0;
}


二、HDU 1846 Brave Game 

题意:

只有一堆n个石子,两个人轮流从这堆石子中子,规定每次至少取一个,最多取m个.最后取光者得胜.

题解:

巴什博弈

若n%(m+1)=0,则先手必败,否则先手必胜。显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的石子,后者取胜.因此我们发现了如何取胜的法则:如果n=(m+1)*r+s,(s≤m),那么先取者要拿走s个石子,如果后取者拿走k(k≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜.

代码:

int main()
{
    int n,m,i,j,k;
    scanf("%d",&k);
    while (k--)
    {
        scanf("%d%d",&n,&m);
        if (n%(m+1))puts("first");else puts("second");
    }
    return 0;
}


三、HDU 1847 Good Luck in CET-4 Everybody! 

题意:

总共n张牌,双方轮流抓牌,每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…,最后抓完牌的人为胜者; 

题解:

暴力SG函数,打表。

代码:

int sg[1010]={0},i,j,k,l,n,m,t,h;
int v[10]={1,2,4,8,16,32,64,128,256,512};
int dfs(int x)
{
    if (sg[x]!=-1)return sg[x];
    bool c[12]={0};
    for (int i=0;i<10;i++)if (v[i]<=x)
    {
        int t=x-v[i];
        sg[t]=dfs(t);
        c[sg[t]]=1;
    }else break;
    for (int i=0;;i++)if (!c[i]) return i;
}

int main()
{
    memset(sg,-1,sizeof sg);
    for (i=0;i<1001;i++)sg[i]=dfs(i);
    while (~scanf("%d",&n))if (sg[n])puts("Kiki");else puts("Cici");
    return 0;
}


四、HDU 1580 Being a Good Boy in Spring Festival 

题意:

有m堆牌,两个人先后取某堆中的任意(不少于一)张牌,最后取完者胜;问先手取胜第一次取牌有多少种取法。

题解:

先求异或和为k。然后k再与每堆异或,若异或值(k^a)小于那堆的石子数(a),说明取到(k^a),此时k^a^(k^a)==0,为必败态,那么自己就是必胜态,就是一种可行解。

代码:

int main()
{
    while(~scanf("%d",&n) && n)
    {
        k=0;
        for (i=1;i<=n;i++)scanf("%d",&a[i]),k^=a[i];
        if (!k)puts("0");else
        {
            j=0;
            for (i=1;i<=n;i++) if ((k^a[i])<a[i])j++;
            printf("%d\n",j);
        }

    }
    return 0;
}


五、 HDU 2147 kiki's game 

题意:

一个n*m的表格,起始位置为右上角,目标位置为左下角,甲先开始走,走的规则是可以向左,向下或者向左下(对顶的)走一格。谁先走到目标位置谁就胜利。在甲乙都采用最佳策略的时候,先走者能否获胜。也是一个巴什博弈的题目。首先画出PN图。

                                                                

只要m或者n有一个是偶数先手就能必胜。

代码:

int main()
{
    while(~scanf("%d%d",&n,&m) && n)
    {
        n--;m--;
        if (n%2==0 && m%2==0 )puts("What a pity!");else puts("Wonderful!");

    }
    return 0;
}


六、HDU 2149 Public Sale

题意:

两人拍卖,每次加价不超过N,超过M就卖给谁,问第一次加价多少才能肯定买到?

题解:

巴什博弈。

代码:

int main()
{
    while(~scanf("%d%d",&n,&m) && n)
    {
        if (m>=n)
        {
            for (i=n;i<m;i++)printf("%d ",i);printf("%d\n",i);
        }else
        if (n%(m+1)==0)puts("none");else printf("%d\n",n%(m+1));
    }
    return 0;
}


七、HDU 2177 威佐夫博弈

题意:

代码:

int n,m,i,j,k,a[200010];
int c[1000010];

int main()
{
    double x=(1+sqrt(5))*0.5;
    memset(c,-1,sizeof c);
    for (i=0;i<=1000000;i++)
    {
        k=i+i*x;
        if (k>1000010)break;
        c[k]=i*x;
    }
    while(~scanf("%d%d",&n,&m) && n)
    {
        if (n>m)swap(n,m);
        int t=(m-n)*x;
        if (t==n)puts("0");else
        {
            puts("1");
            t=m-n;
            int xx=t*x,yy=xx+t;
            if (n-xx == m-yy)printf("%d %d\n",xx,yy);
            if (c[n]!=-1)printf("%d %d\n",c[n],n);
            if (m!=n && c[m]!=-1)printf("%d %d\n",c[m],m);
        }
    }
    return 0;
}