假设在一个名为“ 100个游戏”的游戏中,两个玩家轮流将1到10之间的任何整数添加到奔跑总数中。首先导致奔跑总数达到或超过100的玩家赢得了胜利。那么,如果我们改变游戏规则以使玩家不能重复使用整数怎么办?
例如,如果两个玩家轮流从1..15的公共号码池中抽奖而未替换,直到总数达到== 100。
因此,假设给定一个整数maxChoosableInteger和另一个整数所需的总数,则假设两个玩家都发挥最佳状态,那么确定第一个移动的玩家是否可以强制胜利。
我们始终可以假设maxChoosableInteger不会大于20的值,并且期望的总数不会大于300。因此,如果输入为maxChooseableInteger = 20,并且期望的总数为11,那么结果将为false。不管第一个玩家选择,第一个玩家都会输。
为了解决这个问题,我们将遵循以下步骤-
创建一个名为dp的数组,大小为2 ^ 21
定义一个方法solve()
,将使用n,s和mask。
如果s <= 0,则返回false
如果dp [mask]不为-1,则返回dp [mask]
设置ret:= false
对于1到n范围内的I
ret:= ret OR(resolve(n,s – i,mask XOR 2 ^ i)的反函数)
如果(将掩码I位向右移动)是奇数,则
dp [mask]:= ret
返回ret
在主要方法中,执行以下操作
如果期望总计<= 0,则返回true
适用于0到2 ^ 21范围内的I
dp [i]:= -1
如果需要合计>(前n个数字的总和),则返回false
返回solve(n,desireTotal,0)
让我们看下面的实现以更好地理解-
#include <bits/stdc++.h> using namespace std; class Solution { public: int dp[1 << 21]; bool solve(int n, int s, int mask){ if(s <= 0) return false; if(dp[mask] != -1) return dp[mask]; bool ret = false; for(int i = 1; i <= n; i++){ if(!((mask >> i) & 1)){ ret |= (!solve(n, s - i, (mask ^ (1 << i)))); } } return dp[mask] = ret; } bool canIWin(int n, int desiredTotal) { if(desiredTotal <= 0) return true; for(int i = 0; i < (1 << 21); i++)dp[i] = -1; if(desiredTotal > (n * (n + 1)/ 2))return false; return solve(n, desiredTotal, 0); } }; main() { Solution ob; cout << (ob.canIWin(10,11)); }
10 11
输出结果
0