hdu 3389 Game(博弈——找规律)

Game

Bob and Alice are playing a new game. There are n boxes which have been numbered from 1 to n. Each box is either empty or contains several cards. Bob and Alice move the cards in turn. In each turn the corresponding player should choose a non-empty box A and choose another box B that B<A && (A+B)%2=1 && (A+B)%3=0. Then, take an arbitrary number (but not zero) of cards from box A to box B. The last one who can do a legal move wins. Alice is the first player. Please predict who will win the game.

Input
The first line contains an integer T (T<=100) indicating the number of test cases. The first line of each test case contains an integer n (1<=n<=10000). The second line has n integers which will not be bigger than 100. The i-th integer indicates the number of cards in the i-th box.

Output
For each test case, print the case number and the winner’s name in a single line. Follow the format of the sample output.

Sample Input
2
2
1 2
7
1 3 3 2 2 1 2

Sample Output
Case 1: Alice
Case 2: Bob

题意:1-N带编号的盒子,当编号满足A>B && A非空 && (A + B) % 3 == 0 && (A + B) % 2 == 1则可以从A中取任意卡片到B中,谁不能取了谁就输。

思路:
设n=a+b,则当n为3,9,15,21………的时候满足条件,即n为%6=3的数

则有
((n%6=1)+(n%6=2))%6=(n%6=3)
((n%6=4)+(n%6=5))%6=(n%6=3)
((n%6=3)+(n%6=0))%6=(n%6=3)

说明可以从(n%6=2)->(n%6=1)传递卡片
同理(n%6=5)->(n%6=4),(n%6=0)->(n%6=3)

且1,3,4为这三种情况的终态,即不能转移到其他状态,其他每个状态皆可转移,如 2->1 , 5->4,6->3,7->2,8->1,9->6…..

我们可以它分成一个二分图,
如果可以从A拿卡片到B,连一条从A到B的边。把编号满足(x%6=1||x%6=3||x%6=4)的放在左边,其他的放在右边。不难发现
1)只有从左边到右边的边或从右到左的边。
2)从左边到终态的步数都是偶数步,右边到终态的步数都是奇数步

则有,所有卡片都在偶数步盒子中是必败状态。

因为不论先手将偶数步的盒子中的卡片移走了多少,后手一定可以把这些卡片再往前移动一个盒子,直到移到1 3 4中去为止。

对于只有一个盒子有卡片,而且这个盒子是奇数步盒子来说,先手必胜。

很简单,根据上面的结论,只要先手把这个奇数步盒子中所有卡片全部往下移一个盒子就好了。这样就转移到了先手必败状态。

整个游戏可以看做若干个子游戏的和游戏,偶数步盒子不予考虑,只考虑奇数步盒子中的卡片,这就相当于一个n堆石子的Nim游戏。

在一个奇数步盒子中移走k张卡片,相当于在某一堆石子中取走k个石子。把所有石子取完相当于,所有的卡片都在偶数步的盒子里面,而我们已经证明完这种状态是必败状态了。

所以在代码中就只需要将奇数步盒子中的卡片数异或一下求个Nim和,就能判断胜负了。

代码:

#include
#include
#include
using namespace std;

int main()
{
    int t,k=0,x,n;
    scanf("%d",&t);
    while(++k<=t)
    {
        int ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&x);
            if(i%6==0||i%6==2||i%6==5)
                ans^=x;
        }
        if(ans)
            printf("Case %d: Alice\n",k);
        else
            printf("Case %d: Bob\n",k);
    }
    return 0;
}



参考博客:ACdreamer      Firstdeep      kuangbin

你可能感兴趣的:(-----博弈相关-----,规律题)