版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a54665sdgf/article/details/81625059
题目大意:有一堆石子,有2n个人围成一圈轮流取石子,每个人都有自己取石子的最大数目的限制,取到最后一个石子的输。
这2n个人可以分为两支队伍,每支n人,其中第1 3 5...个人是你的队伍,问你的队伍是否有必胜策略。
解法:这道题给的数据量不大,总状态数不多,可以考虑用dp的方法解决。
设dp(s,p)代表当前石子数为s,轮到第p个人取的时候,这个人所面临的状态是必胜态还是必败态。则可以枚举这个人能取的所有石子的数量i,则状态转移到dp(s-i,(p+1)%n),如果至少有一个i满足dp(s-i,(p+1)%n)是必败态,则dp(s,p)为必胜态,反之则为必败态,以此类推。
递归边界为dp(1,p)为必败态。
我还是习惯用记忆化搜索的方法,代码容易写而且不容易出错。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define FRER() freopen("i.txt","r",stdin)
#define FREW() freopen("o.txt","w",stdout)
using namespace std;
typedef long long LL;
int M[25],n,S,d[(1<<13)+100][25];
int dp(int s,int p)
{
if(~d[s][p])return d[s][p];
for(int i=1; i<=M[p]; ++i)
{
if(s-i<=0)break;
if(!dp(s-i,(p+1)%n))return d[s][p]=1;
}
return d[s][p]=0;
}
int main()
{
//FRER();
while(scanf("%d%d",&n,&S)==2)
{
n<<=1;
for(int i=0; i<n; ++i)
scanf("%d",&M[i]);
memset(d,-1,sizeof d);
printf("%d\n",dp(S,0));
}
return 0;
}