假设在一个名为“ 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