题:http://poj.org/problem?id=2068
题意:
有两个队伍A,B,每个队伍有N个人,交叉坐。即是A(1,3,5,7.....)B(2,4,6,8....)。告诉你每个mi(1<=i<=2n)。
现在有一堆个数为S的石堆,从第1个人开始拿石头,因为是交叉坐所以也就相当于两队轮流拿石头。注意:第i个人拿石头最少拿1个最多拿mi个,拿完石堆中最后一个石头的输。问:A队有没有必胜策略?
分析:
嗯因为数据都不是很大,我们可以用记忆化搜索来求出整个博弈图。如果后继状态有后手必胜(0)那么该状态为先手必胜(1)。如果后继状态全部为先手必胜(1).那么该点状态为后手必胜(0)。当石堆个数为0的时候状态为先手必胜。也就是图的边界。这样用回溯就可以求出所有状态是先手必胜还是后手必胜。
状态表示为 DP[ i ][ j ] 表示轮到第j个人拿,当前还有 i 个石头。

#include<bits/stdc++.h>
using namespace std;
const int M=1e4+4;
int dp[M][30];
int a[M];
int n;
int s;
int dfs(int m,int p){
if(p==2*n)///循环重新来
return dfs(m,0);
if(dp[m][p]!=-1)///记忆化搜索
return dp[m][p];
if(m==0)///达到该状态的人必胜态
return dp[m][p]=1;
for(int i=1;i<=a[p];i++){
if(m<i)
break;
if(dfs(m-i,p+1)==0)///由必败态可转化为必胜态
return dp[m][p]=1;
}
return dp[m][p]=0;///到这里说明之前全都是必胜态。
}
int main(){
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(s,0));
}
return 0;
}
