经典博弈-int

描述 
有两个人玩游戏,给定一个最大可取代数maxChoosableInteger,两个人轮流从1~maxChoosableInteger中取一个数,取过的数不可再取,若其中一方取过以后,所有取过的数的和大于等于desiredTotal,那么这个人获胜。现在给maxChoosableInteger和desiredTotal,问先手是否必胜,假定游戏双方均采取最优策略。你可以假定给出的maxChoosableInteger不超过20,desiredTotal不超过300。

样例 
输入: 
maxChoosableInteger = 10 
desiredTotal = 11 
输出: 
false

说明 
无论先手怎么取数,先手都会输掉游戏。先手可以取到1到10中的任何一个。如果先手取1,那么后手可以取2到10中任何一个。后手如果取10,那么就可以赢得游戏。假如先手取其它的数,那么后手仍然能赢得游戏。

思路 
明显的是,这个全排列问题不能用枚举法来做。1~n的前缀后就是1~n-1的和加上n,用记忆化搜索判断胜利情况。要么当前剩下的desiredTotal小于等于0,要么对于剩下的还未取得数,已经搜索过且是必胜的状态。假设这个状态没有搜索过,就进行判断这个状态,直到遇到判断过的状态或desiredTotal小于等于0。

 1 #include "stdafx.h"
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 class Solution {
 7 public:
 8     vector<int> dp;
 9     vector<bool> used;
10     bool boyi(int maxChoosableInteger, int desiredTotal) {
11         int sum = (1 + maxChoosableInteger)*maxChoosableInteger / 2;
12         if (sum < desiredTotal) {
13             return false;
14         }
15         if (desiredTotal <= maxChoosableInteger) {
16             return true;
17         }
18         dp.resize(1 << maxChoosableInteger);
19         fill(dp.begin(),dp.end(),-1);
20         used.resize(maxChoosableInteger + 1);
21         fill(used.begin(), used.end(), 0);
22         return handler(desiredTotal);
23     }
24     bool handler(int desiredTotal) {
25         if (desiredTotal <= 0)
26             return false;
27         int key = fmt(used);
28         if (dp[key] == -1) {
29             for (int i = 1; i < used.size(); i++) {
30                 if (!used[i]) {
31                     used[i] = true;
32                     if (!handler(desiredTotal - i)) {
33                         dp[key] = -1;
34                         used[i] = false;
35                         return true;
36                     }
37                     used[i] = false;
38                 }
39             }
40             dp[key] = 0;
41         }
42         return dp[key] == 1;
43     }
44     int fmt(vector<bool> & used) {
45         int num = 0;
46         for (int i = 1; i < used.size(); i++) {
47             num <<= 1;
48             if (used[i]) {
49                 num |= 1;
50             }
51         }
52         return num;
53     }
54 };
55 
56 int main()
57 {
58     int maxChoosableInteger, desiredTotal;
59     cin >> maxChoosableInteger >> desiredTotal;
60     Solution sol;
61     bool result=sol.boyi(maxChoosableInteger, desiredTotal);
62     if (result) {
63         cout << "true" << endl;
64     }
65     else {
66         cout << "false" << endl;
67     }
68     return 0;
69 }
View Code

 

posted @ 2018-07-29 09:00  sigmod  阅读(192)  评论(0编辑  收藏  举报