dp_hard_1510石子游戏IV

题目描述

Alice 和 Bob 两个人轮流玩一个游戏,Alice 先手。

一开始,有 n 个石子堆在一起。每个人轮流操作,正在操作的玩家可以从石子堆里拿走 任意 非零 平方数 个石子。

如果石子堆里没有石子了,则无法操作的玩家输掉游戏。

给你正整数 n ,且已知两个人都采取最优策略。
如果 Alice 会赢得比赛,那么返回 True ,否则返回 False 。

示例 1:
输入:n = 1
输出:true
解释:Alice 拿走 1 个石子并赢得胜利,因为 Bob 无法进行任何操作。

示例 2:
输入:n = 2
输出:false
解释:Alice 只能拿走 1 个石子,
然后 Bob 拿走最后一个石子并赢得胜利(2 -> 1 -> 0)。

示例 3:
输入:n = 4
输出:true
解释:n 已经是一个平方数,
Alice 可以一次全拿掉 4 个石子并赢得胜利(4 -> 0)。

示例 4:
输入:n = 7
输出:false
解释:当 Bob 采取最优策略时,Alice 无法赢得比赛。
如果 Alice 一开始拿走 4 个石子,
Bob 会拿走 1 个石子,
然后 Alice 只能拿走 1 个石子,
Bob 拿走最后一个石子并赢得胜利(7 -> 3 -> 2 -> 1 -> 0)。
如果 Alice 一开始拿走 1 个石子,
Bob 会拿走 4 个石子,
然后 Alice 只能拿走 1 个石子,
Bob 拿走最后一个石子并赢得胜利(7 -> 6 -> 2 -> 1 -> 0)。

示例 5:
输入:n = 17
输出:false
解释:如果 Bob 采取最优策略,Alice 无法赢得胜利。

提示:
1 <= n <= 10^5

解析 - 博弈论中的必胜态和必败态

首先来看一个比较简单地的问题:
把原问题中的“任意非零平方数个石子”改为 “一个或两个石子”;

很明显当石子堆中剩余一个或者两个石子的时候当前取石子的人必胜(因为两个人都采取最优策略,不可能有人面对两个石子还傻乎乎的取走一个石子),零个石子必败;

那么剩余三个石子时,当前取石子的人可以选择取一个或者两个石子:
1.如果他取走一个石子后,石子堆剩余两个石子,那么那么他就输了,因为接下来取石子的人面对两个石子是必胜的;
2.如果他取走两个石子后,石子堆剩余一个石子,那么他还是输了,因为接下来取石子的人面对一个石子还是必胜的;

此时我们会发现,当面对当前石子堆的人不论采取何种策略都不能置对手于死地,那么他就必败;但是如果他可以采取某种策略(最优策略)使得对手必败,那么他就必胜;最后我们会得到如下的一个树形的图。

在这里插入图片描述

  • 我们定义一个数组 f f f
    • f [ i ] f[i] f[i]表示的是面对当前的 i i i个石子,先手是否必胜
  • 那么我么可以写出此问题的状态转移方程:
    在这里插入图片描述
  • 那么原问题在本质上和这个简单地问题是一致的,我们只需通过一个循环来判断面对当前石子堆的人分别取走 k k k的平方个石子( k = 1 , 2 , 3 , . . . ; k=1,2,3,...; k=1,2,3,...; k k k的平方小于等于 i i i) 后能否置对手于死地,如果可以那么 f [ i ] = t r u e f[i]=true f[i]=true,否则 f [ i ] = f a l s e f[i]=false f[i]=false;
  • python代码
class Solution:
    def winnerSquareGame(self, n: int) -> bool:
        dp = [False]*(n+1)
        dp[1] = True
        for i in range(2, n+1):
            for j in range(1, int(math.sqrt(i))+1):  # 优化:只需遍历到根号i 即可
                if j*j <= i:  # 需要 所有 平方小于i的dp[idx]均为True, dp[i]才为False
                    if not dp[i-j*j]:  # 否则 dp[i] 为 True
                        dp[i] = True
                        break
        # print(dp)
        return dp[n]

  • T i m e : O ( n 1.5 ) Time:O(n^{1.5}) Time:O(n1.5) - 因为内层循环开根号 n \sqrt{n} n n 1 2 n^{\frac{1}{2}} n21次方
  • S p a c e : O ( n ) Space:O(n) Space:O(n)

Reference

Here

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值