[Leetcode464]我能赢吗?——状态压缩+dfs
1.题目
在 "100 game" 这个游戏中,两名玩家轮流选择从 1
到 10
的任意整数,累计整数和,先使得累计整数和 达到或超过 100 的玩家,即为胜者。
如果我们将游戏规则改为 “玩家 不能 重复使用整数” 呢?
例如,两个玩家可以轮流从公共整数池中抽取从 1 到 15 的整数(不放回),直到累计整数和 >= 100。
给定两个整数 maxChoosableInteger
(整数池中可选择的最大数)和 desiredTotal
(累计和),若先出手的玩家是否能稳赢则返回 true
,否则返回 false
。假设两位玩家游戏时都表现 最佳 。
示例 1:
输入:maxChoosableInteger = 10, desiredTotal = 11
输出:false
解释:
无论第一个玩家选择哪个整数,他都会失败。
第一个玩家可以选择从 1 到 10 的整数。
如果第一个玩家选择 1,那么第二个玩家只能选择从 2 到 10 的整数。
第二个玩家可以通过选择整数 10(那么累积和为 11 >= desiredTotal),从而取得胜利.
同样地,第一个玩家选择任意其他整数,第二个玩家都会赢。
示例 2:
输入:maxChoosableInteger = 10, desiredTotal = 0
输出:true
示例 3:
输入:maxChoosableInteger = 10, desiredTotal = 1
输出:true
提示:
1 <= maxChoosableInteger <= 20
0 <= desiredTotal <= 300
2.思路
这道题数据范围比较小,可以想到是状态压缩的情况,但是状态十分复杂,我是参考题解想的。一个数拿回不能放回,即只能使用一次,因此需要使用一个数据结构记录状态,C++和Java都可以使用Map作为记录。状态就是当前这个数有没有使用,使用的话这一位就为1;如100是3。第i位为1表示i被使用。
如果是先手必输的话 应该是 所有情况都是后手必胜;如果是先手必胜的话 是存在一种情况是后手必输
3.代码
class Solution {
public:
bool canIWin(int maxChoosableInteger, int desiredTotal) {
if(((1+maxChoosableInteger)*maxChoosableInteger*0.5)<desiredTotal)
return false;
return dfs(maxChoosableInteger,0,desiredTotal,0);
}
bool dfs(int maxChoosableInteger, int userNumbers, int desiredTotal, int currentTotals)
{
if(memory.count(userNumbers)==0)
{
bool res=false;
for(int i=0;i<maxChoosableInteger;i++)
{
int temp=((userNumbers>>i)&1);
if( temp==0)
{
int sum=i+1+currentTotals;
if(sum>=desiredTotal)
{
res=true;
break;
}
//判断对方是否输
int x=userNumbers |(1<<i);
int total=currentTotals+i+1;
if(!dfs(maxChoosableInteger,x,desiredTotal,total))
{
res=true;
break;
}
}
}
memory.insert({userNumbers,res});
}
return memory.find(userNumbers)->second;
}
map<int,bool> memory;
};