1. 程式人生 > >【博弈 && dfs】POJ

【博弈 && dfs】POJ

Step1 Problem:

有 s 個石頭,有 2*n 個人,分成兩隊交叉坐著分別是 1, 3, 5,…n-1. 和 2, 4, 6,…n. 第 i 個人可以拿走不多於 a[i] 個石頭,從玩家 1 開始拿石頭 1 到 2 到 3 到….n 到 1 一直迴圈,拿走最後一顆石頭的團隊失敗。
資料範圍:
1<=n<=10, 1<=a[i]<=16, 1<=s<=2^13

Step2 Ideas:

dp[s][i] == 1:當前到玩家 i 剩餘 s 個石頭必勝
dp[s][i] == 0:當前到玩家 i 剩餘 s 個石頭必敗
dp[s][0] 就是結果
當前狀態的下一個狀態是必敗狀態,當前狀態為必勝狀態。
當前狀態的下一個狀態全是必勝狀態,當前狀態為必敗狀態。
然後搜尋即可

Step3 Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 9000;
const int inf = 0x3f3f3f3f;
int a[100];
int dp[N][25], s, n;
int dfs(int x, int i)//剩餘的石子,到第幾個人
{
    //printf("%d %d\n", x, i);
    if(x <= 0) return dp[0][i] = 1;//已經沒有石子可拿,所以當前狀態必勝
if(dp[x][i] != -1) return dp[x][i];//已經搜尋過了不必再搜尋了 int res = inf; for(int j = 1; j <= a[i] && j <= x; j++) { res = min(res, dfs(x-j, (i+1)%(2*n))); } if(res == 0) return dp[x][i] = 1;//下一個狀態存在必敗狀態,當前狀態必勝 else return dp[x][i] = 0; } int main() { while(~scanf
("%d", &n) && n) { memset(dp, -1, sizeof(dp)); scanf("%d", &s); for(int i = 0; i < 2*n; i++) scanf("%d", &a[i]); dfs(s, 0); printf("%d\n", dp[s][0]); } return 0; }