开学回归力扣:第九题——1025. 除数博弈(动态规划解决博弈问题)

1025. 除数博弈

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 False。假设两个玩家都以最佳状态参与游戏。

示例 1:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
示例 2:

输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。
 

提示:

1 <= N <= 1000

题解:

此类博弈类问题常常采用动态规划思想进行解决。
即对于数字为N时的输赢情况我们可以使用一个数组dp来专门的去存取。
通过分析可以知道找准动态规划问题的边界,即为数字1,2的输赢情况。

接着开始分析题目:

由于我们的目标是找到爱丽丝的输赢情况,我们可以先令数组dp全部存储0,即为任意数字时爱丽丝均输,接着只要求出哪几个数字爱丽丝赢重新填入数组即可。
那么爱丽丝什么时候会赢呢?
需要注意的是这一类博弈问题常常都是有一个条件,即均以最佳状态参与游戏,也就是说如果存在能赢的方案的话,由于状态是最佳的那么一定能想到这个最佳方案。送一要求爱丽丝赢的情况即在爱丽丝拿去若干个后留给鲍勃的是一种必输的方案即可。

我们可以从几个例子来看:
当轮到爱丽丝且没拿时N为2时,爱丽丝必胜。

当N为3时,爱丽丝拿一个后变为两个,此时与上面的情况相同,不过人物由爱丽丝变成了鲍勃,因此我们由上述结论直接推出鲍勃赢。此时我们又得到新结论:当轮到某人且他没拿时N为3时,他必输。

当N为4时,若爱丽丝拿1个后,此时鲍勃对应N为3,此时由上述结论知他必输;

若爱丽丝拿2个后,由上述结论可知此时鲍勃对应N为2,鲍勃必胜。

因此我们不难发现后面数字的结论都是依照在前面的基础上得到的,因此我们要想得到数字为N时爱丽丝的输赢情况,我们只要把0-N-1的输赢状态均存储进去即可算出N的情况。
所以我们创建一个循环遍历,因为我们只要找出一种能使鲍勃必输的方案我们就可以让爱丽丝胜利(因为我们是先手),因此确定好一个N后,由于题目要求我们需要先找(1,N)范围的N的因数,因此我们再创建一个循环遍历1-N,找到其范围内的一个因数且在总N减去你找到的那个因数得到的新N对应的状态是必输的状态即可。

注意的是看样子数组dp是对应的爱丽丝的输赢情况,其实同样也对应着鲍勃的输赢情况,因为你将先手的第一步去掉,且总N变成新的N后,此时的先手也就变成了鲍勃。

代码:

bool divisorGame(int N){
    
    
    int dp[N+1];
    if(N==1)
    {
    
    
        return 0;
    }
    if(N==2)
    {
    
    
        return 1;
    }
    memset(dp,0,sizeof(int)*(N+1));
    dp[1]=0;
    dp[2]=1;
    for(int i=3;i<=N;i++)
    {
    
    
        for(int j=1;j<i;j++)
        {
    
    
            if(i%j==0&&dp[i-j]==0)//此时即对应找到一个因数且总数减去因数后留下的这个数形成的新N对应先手的是一种必输的情况
            //而此时由于爱丽丝已经操作过了,所以此时的先手对应的就是鲍勃了,所以这里也就是鲍勃的必输情况了
            {
    
    
                dp[i]=1;
            }
        }
    }
    return dp[N];
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/114730972