Can I Win

36 篇文章 0 订阅
13 篇文章 0 订阅

[leetcode]Can I Win

链接:https://leetcode.com/problems/can-i-win/description/

Question

In the “100 game,” two players take turns adding, to a running total, any integer from 1..10. The player who first causes the running total to reach or exceed 100 wins.

What if we change the game so that players cannot re-use integers?

For example, two players might take turns drawing from a common pool of numbers of 1..15 without replacement until they reach a total >= 100.

Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally.

You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal will not be larger than 300.

Example

Input:
maxChoosableInteger = 10
desiredTotal = 11

Output:
false

Explanation:
No matter which integer the first player choose, the first player will lose.
The first player can choose an integer from 1 up to 10.
If the first player choose 1, the second player can only choose integers from 2 up to 10.
The second player will win by choosing 10 and get a total = 11, which is >= desiredTotal.
Same with other integers chosen by the first player, the second player will always win.

Solution

class Solution {
public:
  int maxn;
  vector<unordered_map<int, bool> > dp;
  bool canIWin(int maxChoosableInteger, int desiredTotal) {
    maxn = maxChoosableInteger;
    if (maxn >= desiredTotal) return true;
    if (maxn*(maxn+1)/2 < desiredTotal) return false;
    dp.resize(desiredTotal+1);
    return canWin(desiredTotal, 0);
  }
  bool canWin(int target, int visited) {
    // 表示target和visited状态已经被访问过
    if (dp[target].find(visited) != dp[target].end()) {
      return dp[target][visited];
    } else {
      for (int i = 1; i <= maxn; i++) {
        // 使用mask进行挑数
        int mask = 1<<i;
        // 表示i没有访问过
        if ((mask & visited) == 0 && 
          // 表示可以直接拿i就赢了 或者是 对手输了
          (i >= target || !canWin(target-i, visited | mask))) {
          dp[target][visited] = true;
          return true;
        }
      }
    }
    dp[target][visited] = false;
    return false;
  }
};

思路:这道题是博弈题,也就是双方都很不傻的情况下如何考虑进行博弈的问题。CanIWin函数中直接将两种简单情况去掉,一种是可以选择的数字大于目标值(必定赢),一种是所有数字加起来也达不到target(必定输)。下一步调用CanWin函数进入下一步的递归(CanWin不是针对自己来说的,对手赢了CanWin也是返回true)。这里递归步骤多会超时,所以需要进行状态压缩【保存子问题的解的,主要思想是把所有可能的状态(子问题)用一个数据结构(通常是整数)统一表示,再用map把每个状态和对应结果关联起来,这样每次求解子问题时先find一下,如果map里面已经有该状态的解就不用再求了;同样每次求解完一个状态的解后也要将其放入map中保存】。每个状态不同之处有两个:

  1. target
  2. 可以选的数(这里的数是不放回地选择)

所以这里使用vector[target][visited]进行标记即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值