SRM 511 DIV1 500pt(DP)

題目簡述spa

給定n個數,兩我的輪流取數,和以前兩我的的取的數或起來,誰不能取數或者誰取到的數和以前的數或值爲511誰輸,問誰可以贏?code

題解blog

剛開始的想法是直接搜,不過須要記錄取過的值的狀態,2^50顯然超時。。。對於當前或值cur,或上一個數num,只有兩種狀況,要麼是 cur|num==cur,get

對於這種數,只是把這個狀態直接給下一個玩家,起到延緩一步的做用,他們的選取順序對局面沒有影響,能夠先所有輪流取掉,若是這種數的個數大於當前已經取的數的數量,那麼咱們還能夠選擇這種數,若是選擇這個數能夠致使下一個局面必敗,那麼當前這個局面能夠必贏。第二種狀況就是cur|num!=cur,num確定是沒有取過的,若是存在一個數num致使下一個局面必敗,那麼當前這個局面也是必勝的。若是下一個局面必勝,那麼當前局面就是必輸的,咱們能夠用記憶化搜索實現上述過程~~~string

代碼:it

 1 vector<int>card;
 2 int dp[55][555], n;
 3 int dfs(int th, int mask)
 4 {
 5     if (mask == 511) return 1;
 6     if (th == n) return 0;
 7     if (~dp[th][mask]) return dp[th][mask];
 8     int cnt = 0;
 9     for (int i = 0; i < n; i++) if ((card[i] | mask ) == mask) cnt++;
10     if (cnt > th && !dfs(th + 1, mask)) return dp[th][mask] = 1;
11     for (int i = 0; i < n; i++) if ((card[i] | mask ) != mask)
12         {
13             if (!dfs(th + 1, mask | card[i])) return dp[th][mask] = 1;
14         }
15     return 0;
16 }
17 class FiveHundredEleven
18 {
19 public:
20     string theWinner(vector <int> cards)
21     {
22         card = cards;
23         n = card.size();
24         memset(dp, -1, sizeof(dp));
25         return dfs(0, 0) ? "Fox Ciel" : "Toastman";
26     }
27 };
相關文章
相關標籤/搜索