LeetCode 464 Can I Win 题解

来源:互联网 发布:java类的实例化过程 编辑:程序博客网 时间:2024/06/10 10:48

题意简述:给定两个值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);    }};
0 0
原创粉丝点击