您的位置:首页 > 其它

LeetCode 464 Can I Win 题解

2017-04-27 18:43 344 查看
题意简述:给定两个值n和desiredTotal,要求两位玩家从整数1,2,……,n中依次取数,每个数只能取一次,每个取出的数都会加到一个和数上,最先使和数大于或等于desiredTotal的玩家获胜。问玩家1(先取数的)是否必胜。假设两位玩家都会作出最优选择。

输入:两个值n和desiredTotal。

输出:一个bool值,表示玩家1是否获胜。

示例:对于n=10和desiredTotal=11,玩家1必败,因为无论取1到10哪个数,玩家2都能再取一个数使和达到11。

题解:

采用dfs+map辅助记忆化搜索。使用二进制串记录当前状态下每个数有没有被拿(数可用为1,不可用为0)。dp(bits, remain)为true,当且仅当对于bits里面所有可用的i,存在dp(bits & ~(1 << i), remain-i)为false。简单的解释:对于当前状态,只要在所有的取法中存在至少一种取法使对方必败,那么这个状态是必胜的。终结状态是remain <= 0,这意味着已经取的数之和已经超过desiredTotal,因而是必败状态。

使用unorder_map记录dfs过程中产生中间状态dp的值。注意unorder_map的key值可以只用bits,这是因为remain可以通过desiredTotal减去已取的数(bits对应位为1)之和得到。

算法实现如下,空间复杂度是O(2n),因为状态数就是2n。在这题中n<=20,因此2n是可接受的。

class Solution {
private:
unordered_map<unsigned long, bool> mymap;
int _maxInteger;

bool dp(bitset<20>& mybit, int remain) {
if(mymap.find(mybit.to_ulong()) != mymap.end())
return mymap[mybit.to_ulong()];

if(remain <= 0) {
mymap[mybit.to_ulong()] = false;
return false;
}

for(int i = 1;i <= _maxInteger;i++)  {
if(!mybit[i-1]) {
mybit.set(i-1);

bool temp = dp(mybit, remain-i);
mybit.reset(i-1);
if(!temp) {
mymap[mybit.to_ulong()] = true;
return true;
}
}
}

mymap[mybit.to_ulong()] = false;
return false;
}
public:
bool canIWin(int maxChoosableInteger, int desiredTotal) {
_maxInteger = maxChoosableInteger;

bitset<20> mybit;
mybit.reset();

if(desiredTotal <= 0) return true;
if((1+maxChoosableInteger)*maxChoosableInteger/2 < desiredTotal)
return false;
return dp(mybit, desiredTotal);
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode