我最近在网上找到了此问题的解决方案(来自leetcode.com的原始信息):
在“ 100个游戏”中,两个玩家轮流将1..10中的任何整数添加到连续总计中。首先使跑步总数达到或超过100的玩家。 如果我们改变游戏规则以使玩家不能重复使用整数怎么办? 例如,两个玩家可能轮流从1..15的公共号码池中抽奖,而没有替换,直到总数达到> = 100。
给定一个整数maxChoosableInteger
和另一个整数desiredTotal
,假设两个玩家都发挥最佳状态,那么确定第一个移动的玩家是否可以强制胜利。
您始终可以假设maxChoosableInteger
不大于20,desiredTotal
不大于300。
int canWin(int *dp, int v, int m, int total) {
int i, hewins;
if (dp[v] != -1) return dp[v]; // already resolved
for (i = m; i >= 1; i --) {
if (v & (1 << (i - 1))) continue;
v |= (1 << (i - 1));
if (i >= total) {
dp[v] = 1; // resolve to win
return 1;
}
hewins = canWin(dp, v, m, total - i);
if (!hewins) return 1;
v &= ~(1 << (i - 1)); // not able to resolve, try with different number
}
dp[v] = 0; // resolve to loose
return 0;
}
bool canIWin(int maxChoosableInteger, int desiredTotal) {
int w, dp[1 << 20];
// none can win
if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) return false;
//dp = calloc((1 << (maxChoosableInteger)), sizeof(int));
//assert(dp);
memset(dp, -1, (1 << (maxChoosableInteger)) * sizeof(int));
w = canWin(dp, 0, maxChoosableInteger, desiredTotal);
//free(dp);
return w;
}
在上面的代码中,在3个主要实例中使用了左移。
memset(dp, -1, (1 << (maxChoosableInteger)) * sizeof(int));
和
dp[1 << 20]
以及类似以下内容的所有实例:
if (v & (1 << (i - 1))) continue;
该问题的解决方案是递归的,并且这个问题可以递归地解决,但是首先我不确定为什么您需要这么大的数组来存储所有递归调用。每个输入最多应有20个递归调用(因为canIWin(maxinteger, total) = canIWin(maxInteger - 1), total)
OR
canIWin((maxInteger - 2), total)
OR
... canIWin(1, total)
(实际上不能转到1因为逻辑上的原因,但这只是使想法得以传播)
对于为什么使用这种左移的任何解释将不胜感激。