【LeetCode】一种博弈思路 minimax(共5题)

【375】Guess Number Higher or Lower II 

【464】Can I Win (2019年2月20日,谷歌tag,M)

给了一个1-100的游戏,游戏规则是,两个选手,player1每次从1-100中抽取一个数字,player2每次也从1-100中抽取一个数字,不能重复抽取相同的数字。直到某个player抽取到一个数,所有轮次中每个player抽取的数字加和大于等于target(target是提前给定的)。问player1能不能赢这个游戏。

本题的题目意思是把100换成一个变量叫做 maxChoosableInteger。问 player1 能不能赢这个游戏。

题解:这是一棵博弈树的问题。解空间如下图:

裸的dfs搜索方法如下:对于当前的局面,我们尝试用一个没有用过的数作为当前的解,然后dfs到下一个局面。

如果下个局面返回了false,就是对手不能赢,那我肯定非常高兴的马上返回了true,因为这个局面我能赢。(注意返回的时候要把当前局面用过的数字清空。回溯。不能忘。

但是如果下个局面返回了true,我就会认真反思自己,然后后悔当前局面的走法(是的,就是这么的无赖)去换一种新的走法。

那么对于当前局面的前一个局面来说,对手看到我返回了true,那他也可以反悔啊,他内心os:老子也不这么走了,我也要换一个走法。于是他就继续遍历他解空间的下一个解,直到他在当前空间找到了一个解,这个解能让他在当前空间赢,或者他找遍了所有的可能解,都赢不了,他只好认输,"我在当前空间赢不了,我返回false"。

 1 class Solution {
 2 public:
 3     bool canIWin(int maxChoosableInteger, int desiredTotal) {
 4         if (desiredTotal <= 0) {return true;}
 5         if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) {return false;}
 6         string used(maxChoosableInteger, '0');
 7         int sum = 0;
 8         return canIWin(maxChoosableInteger, desiredTotal, sum, used);
 9     }
10     bool canIWin(int maxChoosableInteger, int desiredTotal, int sum, string& used) {
11         if (sum >= desiredTotal) {return false;}
12         for (int i = 1; i <= maxChoosableInteger; ++i) {
13             if (used[i-1] == '1') { continue; } //如果当前的数用过了,那么就换下一个能用的数
14             used[i-1] = '1';
15             if (canIWin(maxChoosableInteger, desiredTotal, sum + i, used) == false) {
16                 //到这里需要回溯。如果下一个局面为false的话,就说明当前局面能赢。
17                 //但是你想象一下如果你是一个玩家,当对手告诉你这个局面对手能赢的时候,你会怎么做,
18                 //肯定是返回到一个有一个解-对手不能赢的层次,然后去dfs那个解空间。
19                 used[i-1] = '0'; 
20                 return true;
21             }
22             used[i-1] = '0';
23         }
24         return false;
25     }
26 };
View Code

再加上可以记忆化或者状态压缩的技巧。用个memo。

 1 class Solution {
 2 public:
 3     bool canIWin(int maxChoosableInteger, int desiredTotal) {
 4         if (desiredTotal <= 0) {return true;}
 5         if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) {return false;}
 6         string used(maxChoosableInteger, '0');
 7         int sum = 0;
 8         return canIWin(maxChoosableInteger, desiredTotal, sum, used, 0);
 9     }
10     unordered_map<string, bool> memo;
11     bool canIWin(int maxChoosableInteger, int desiredTotal, int sum, string& used, int player) {
12         if (sum >= desiredTotal) {return false;}
13         if (memo.find(used) != memo.end()) {return memo[used];}
14         string key = used;
15         memo[key] = false;
16         for (int i = 1; i <= maxChoosableInteger; ++i) {
17             if (used[i-1] == '1') { continue; }
18             used[i-1] = '1';
19             if (canIWin(maxChoosableInteger, desiredTotal, sum + i, used, 1 - player) == false) {
20                 memo[key] = true;
21                 used[i-1] = '0';
22                 return true;
23             }
24             used[i-1] = '0';
25         }
26         return false;
27     }
28 };
View Code

【486】Predict the Winner 

【843】Guess the Word 

913】Cat and Mouse 

猜你喜欢

转载自www.cnblogs.com/zhangwanying/p/9964702.html