Hdu 4111 Alice and Bob(博弈+记忆化搜索)

题目链接

Alice and Bob

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1587    Accepted Submission(s): 575


Problem Description
Alice and Bob are very smart guys and they like to play all kinds of games in their spare time. The most amazing thing is that they always find the best strategy, and that's why they feel bored again and again. They just invented a new game, as they usually did.
The rule of the new game is quite simple. At the beginning of the game, they write down N random positive integers, then they take turns (Alice first) to either:
1. Decrease a number by one.
2. Erase any two numbers and write down their sum.
Whenever a number is decreased to 0, it will be erased automatically. The game ends when all numbers are finally erased, and the one who cannot play in his(her) turn loses the game.
Here's the problem: Who will win the game if both use the best strategy? Find it out quickly, before they get bored of the game again!
 

Input
The first line contains an integer T(1 <= T <= 4000), indicating the number of test cases.
Each test case contains several lines.
The first line contains an integer N(1 <= N <= 50).
The next line contains N positive integers A 1 ....A N(1 <= A i <= 1000), represents the numbers they write down at the beginning of the game.
 

Output
For each test case in the input, print one line: "Case #X: Y", where X is the test case number (starting with 1) and Y is either "Alice" or "Bob".
 

Sample Input
   
   
   
   
3 3 1 1 2 2 3 4 3 2 3 5
 

Sample Output
   
   
   
   
Case #1: Alice Case #2: Bob Case #3: Bob
 

Source
2011 Asia ChengDu Regional Contest
 

Recommend
We have carefully selected several similar problems for you:   4114  4115  4119  4118  4112 

题意:两个人博弈,N堆石子,每次可以拿掉一个石子,也可以把两堆合并成一堆,不能操作的那个人输,问先手赢还是输。


题解:假设每堆石子的个数都大于一。如果一个 人面对状态的最大操作数为奇数,那么他可以贪心的先把石子合并成一堆,这样的操作数就是最大操作数并且为奇数,这个人一定赢。如果一个人面对状态的最大操作数位偶数,由于没有1,另一个一定可以贪心的让最大操作数不变,那么这个人一定输。那么能够影响操作数的奇偶性的只有1。所以我们可以先把非1的堆合成一堆。那么现在的状态就是1的个数和非1的堆的大小,非1的堆的大小不超过6*10^4,1的个数不超过10^3,。总状态数位10^7的数量级,我们可以用记忆化搜索的方法,求出每个状态是必胜点还是必败点。其实有效状态数远小于10^7,复杂度就是状态数,<O(10^7)。

我们用dp[ i ][ j ]表示非1堆的大小为 i ,1的个数为 j 的状态是必胜点还是必败点。石子怎么操作就怎么转移就是了。转移的时候要注意,非1堆的大小不能为1。

详情见代码:

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<queue>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<stack>
#define nn 55
#define mod 1000
#define inff 0x3fffffff
typedef __int64 LL;
using namespace std;
int n;
int dp[60000][55];
int a[nn];
int dfs(int sum,int yi)
{
    if(dp[sum][yi]!=-1)
        return dp[sum][yi];
    dp[sum][yi]=0;
    if(yi==0)
    {
        return dp[sum][yi]=sum%2;
    }
    if(sum==1)//非1堆的大小不能为1
    {
        dp[sum][yi]=dfs(0,yi+1);
        return dp[sum][yi];
    }
    dp[sum][yi]|=(1-dfs(sum,yi-1));//拿掉一个1
    if(sum)
    {
        dp[sum][yi]|=(1-dfs(sum-1,yi));//从非1堆中拿掉一个石子
        dp[sum][yi]|=(1-dfs(sum+1,yi-1));//将一个1合并到非1堆
    }
    if(yi>=2)//合并两个1
    {
        if(sum)
            dp[sum][yi]|=(1-dfs(sum+3,yi-2));
        else
            dp[sum][yi]|=(1-dfs(sum+2,yi-2));
    }
    return dp[sum][yi];
}
int main()
{
    int i,t;
    int cas=1;
    memset(dp,-1,sizeof(dp));
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int sum=0,yi=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]==1)
                yi++;
            else
                sum+=a[i]+1;
        }
        if(sum)
            sum--;
        printf("Case #%d: ",cas++);
        if(dfs(sum,yi))
        {
            puts("Alice");
        }
        else
            puts("Bob");
    }
    return 0;
}


你可能感兴趣的:(ACM,DFS,博弈)