464. 我能赢吗

112 阅读1分钟

464. 我能赢吗

思路:

直接搜索即可

主要难点在于考虑搜索函数的状态,观察注意到最多只有20个整数,我们可以用一个int(32位)完全表示这个整数,一个int的第i位为0则代表这个整数i还没有被拿走,反之则已经拿走

假设我们有函数f,可以返回一个状态下能否必胜,那么对于A(博弈者)来说,f的返回值就是该状态下,穷尽所有可行的操作,能不能胜利

最后我们再用一个mp存储之前算出的结果,避免重复计算

class Solution {
public:
int mp[2<<21]; // 0 为未搜索,1为胜,2为败
    bool find(int status,int sum,int n){ // find 返回这种情况下穷尽所有操作能不能赢
        if(mp[status]!=0){// 如果status已经被搜索了,返回结果
            return mp[status]==1;
        }
        if(sum<=0){ // 如果和已经超过值了,则说明已经输了
            mp[status]=2;
            return false;
        }

        for(int i=1;i<=n;i++){
            if(((status>>i)&1)==0) // 如果这个数字还没有被拿走
            if(find(status|(1<<i),sum-i,n)==0){ // 尝试拿走他,看看这个状态是不是对方的必败态
                mp[status]=1;
                return true;
            } 
        }
        mp[status]=2;
        return false;
    }

    bool canIWin(int mx, int desiredTotal) {
        if(mx*(mx+1)/2<desiredTotal) return false; // 如果所有数字之和都超不过desiredTotal,则都败
        if(!desiredTotal) return 1; // 如果一开始desiredTotal则说明一开始就赢了
        // 前面两行是特判
        return find(0,desiredTotal,mx);
    }
};