HDU 2149 Public Sale(巴什博奕)

题目地址:点击打开链接

思路:

一.巴什博奕(Bash Game) 

只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。  
显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。 一般方法: 
步骤1:将所有终结位置标记为必败点(P点); 
步骤2: 将所有一步操作能进入必败点(P点)的位置标记为必胜点(N点) 
步骤3:如果从某个点开始的所有一步操作都只能进入必胜点(N点) ,则将该点标记为必败点(P点) ; 

步骤4: 如果在步骤3未能找到新的必败(P点),则算法终止;否则,返回到步骤2

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>

using namespace std;

int main()
{
    int n,m;
    int i;
    while(~scanf("%d%d",&m,&n))
    {
        if(m % (n+1) == 0)//无论第一个人怎么取,第二个人只要保证剩下的为n+1的倍数即可获胜
        {
            printf("none\n");
            continue;
        }
        else
        {
            if(m <= n)//第一个人直接可以取完
            {
                printf("%d",m);
                for(i=m+1; i<=n; i++)
                {
                    printf(" %d",i);
                }
                printf("\n");
            }
            else//把上面介绍的s取走,这样就就能边被动为主动,让自己变为上面意义上的第二个人
            {
                printf("%d\n",m %(n+1));
            }
        }
    }
    return 0;
}


你可能感兴趣的:(HDU 2149 Public Sale(巴什博奕))