POJ 2068 Nim (dp博弈)
阿新 • • 發佈:2017-12-21
== 超過 cst memset put pre 轉移 sca nbsp
題意:
共n輪,s個石頭和兩隊人,兩隊人輪流拿,第i輪兩隊分別只能拿1~M[(2*i-1)%(2*n)]和1~M[(2*i)%(2*n)]個石頭,拿到最後那個石頭的隊輸;
就拿最後一組樣例來說,循環中共3輪,共97個石頭,第一輪兩隊分別拿不超過8個和7個石頭,第二輪6個和5個,第三輪4個和3個,然後又是8個和7個......
Input
n S M[1] M[2] . . . M[2*n]
1 <= n <= 10, 1 <= Mi <= 16, and 1 <= S < 2^13.Output
贏輸出1,輸輸出0Sample Input
1 101 4 4 1 100 4 4 3 97 8 7 6 5 4 3 0
Sample Output
0 1 1
必勝態有至少一種方法轉移到必敗態
必敗態只能轉移到必勝態
然後就可以dp了
dp[i][j]表示第i次還剩下j個石頭時,1為勝,0為敗
然後dfs一下,記憶化一下已經訪問過的就好了
#include<cstdio> #include<cstring> using namespace std; int a[20],dp[20][9000],n; int dfs(int k,int left) { if(dp[k][left]!=-1) return dp[k][left]; if(left==0) return dp[k][left]=1; //當剩下石頭數量是0時,是勝的 for(int i=1;i<=a[k]&&i<=left;i++) { if(!dfs((k+1)%(2*n),left-i)) return dp[k][left]=1; //如果可以轉移到必敗態,那麽就是必勝態 } return dp[k][left]=0; } int main() { int s; while(~scanf("%d",&n)&&n) { scanf("%d",&s); for(int i=0;i<2*n;i++) scanf("%d",&a[i]); memset(dp,-1,sizeof(dp)); printf("%d\n",dfs(0,s)); } return 0; }
POJ 2068 Nim (dp博弈)