Alice and Bob HDU - 4111(SG函数,NP定理)

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

题意: n堆石子。A和B轮流取。可以取一个,也可以合并两堆。取不了的人输了。
思路:
将石子分为数目为1的堆和数目不为1的堆。
设数目为1堆的个数为x,不为1的堆操作次数为y。y为∑a[i] + n - 1。n个a[i],求数目和后,加上n - 1次合并。

设为dp(x, y)。可以记忆化搜索。子状态如果返回0,那么由此状态转移到必败态,由NP定理,当前状态为必胜态。枚举几种操作搜索即可。

有大神通过NP定理推出了公式,可以参考:
https://blog.csdn.net/keshuai19940722/article/details/40952653

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int a[55];
int dp[55][50055];

bool DP(int x,int y)
{
    if(dp[x][y] != -1)return dp[x][y];
    dp[x][y] = 0;
    if(y == 1)//y剩下的1加入到x中
    {
        dp[x][y] = DP(x + 1,0);
    }
    else if(x >= 1 && !DP(x - 1,y))//去掉一个1
    {
        dp[x][y] = 1;
    }
    else if(x >= 1 && y >= 1 && !DP(x - 1,y + 1))//1合并到其他数
    {
        dp[x][y] = 1;
    }
    else if(x >= 2 && ((y && !DP(x - 2,y + 3)) || (y == 0 && !DP(x - 2,2))))//2个1合并
    {
        dp[x][y] = 1;
    }
    else if(y >= 2 && !DP(x,y - 1))//减少y中的一个1
    {
        dp[x][y] = 1;
    }
    return dp[x][y];
}

int main()
{
    memset(dp,-1,sizeof(dp));
    int T;scanf("%d",&T);
    int kase = 0;
    while(T--)
    {
        int n;scanf("%d",&n);
        int x = 0,y = 0;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i] == 1)x++;
            else y += a[i] + 1;
        }
        y--;
        if(DP(x,y))printf("Case #%d: Alice\n",++kase);
        else printf("Case #%d: Bob\n",++kase);
    }
    return 0;
}

发布了628 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104011989