先贴一个链接http://blog.csdn.net/qq1169091731/article/details/51942752
度娘和csdn都是好东西
洛谷p1857取石子
博弈论的题目,对于一种情况,如果有前驱情况为必败态,则该情况必为必胜态,若前驱情况都为必胜态,则该情况为必败态。
且若当前情况为必胜态,则应从步数最少的前驱必败态转换而来(尽快胜利),
若当前情况为必败态,则应从步数最多的必胜态转换而来(阻止对方胜利)。
s[i][0]表示i个石子时的步数,s[i][1]=-1表示当前为必败态,s[i][1]=1表示为必胜态。
p数组存质数,pr数组为判定用。
#include<bits/stdc++.h> using namespace std; int n,s[20010][2]={0},a[20]={0},pr[20010]={1,1},p[3000]={0},ma=0,sum=0; inline int read(int &num) { num=0; char c=getchar(); for(;isdigit(c)==0;c=getchar()); for(;isdigit(c)!=0;c=getchar())num=num*10+c-'0'; } inline void init() { read(n); for(int i=1;i<=n;++i) { read(a[i]); if(a[i]>ma)ma=a[i];//寻找最大值,以便线下操作 } return; } inline void first()//筛法,pr[i]=0表示质数,pr[i]=1表示合数 { for(int i=2;i<=ma;++i) if(pr[i]==0) { p[++sum]=i;//存储质数,可以节省时间 for(int j=i+i;j<=ma;j+=i)pr[j]=1; } return; } inline void dp() { s[0][1]=-1;s[0][0]=0; s[1][1]=-1;s[1][0]=0; s[2][1]=1;s[2][0]=1; s[3][1]=1;s[3][0]=1;//初始化几个点 for(int i=4;i<=ma;++i) for(int j=sum;j>=1;--j)//j不能反过来,会WA if(p[j]<=i) { if(s[i-p[j]][1]==-1)//前驱为必败态 if(s[i][1]==0||s[i][1]==-1)//如果未判定状态 { s[i][1]=1;//置必胜态 s[i][0]=s[i-p[j]][0]+1; } else s[i][0]=min(s[i][0],s[i-p[j]][0]+1);//选取最小值 if(s[i-p[j]][1]==1)//前驱为必败态 if(s[i][1]==0)//如果未置状态 { s[i][1]=-1; s[i][0]=s[i-p[j]][0]+1; } else if(s[i][1]==-1)//如果已置必败态 s[i][0]=max(s[i][0],s[i-p[j]][0]+1);//寻找最大值 } return; } inline void print() { for(int i=1;i<=n;++i) if(s[a[i]][1]==-1) printf("-1\n"); else printf("%d\n",s[a[i]][0]); return; } int main() { init(); first(); dp();
洛谷p2734游戏A game
区间dp,设s[i][j]表示从第i个数到第j个数取能所获得的最大值,则这次选取一定让下一次的选取的最大值最小,
即形成s[i+1][j]和s[i][j-1]中更小的。
#include<bits/stdc++.h> using namespace std; int n,s[110][110]={0},a[110]={0},sum[110]={0}; inline int read(int &num)//熟悉的读入优化 { num=0; char c=getchar(); for(;isdigit(c)==0;c=getchar()); for(;isdigit(c)!=0;c=getchar())num=num*10+c-'0'; } inline void init() { read(n); for(int i=1;i<=n;i++) { read(a[i]); sum[i]=sum[i-1]+a[i]; } return; } inline void dp() { for(int i=1;i<=n;i++)s[i][i]=a[i]; for(int len=2;len<=n;len++) for(int i=1;i<=n-len+1;i++) { int j=i+len-1; s[i][j]=sum[j]-sum[i-1]-min(s[i+1][j],s[i][j-1]); } return; } int main() { init(); dp(); printf("%d %d",s[1][n],min(s[1][n-1],s[2][n]));//第一人会让第二人获得的最小,所以用min return 0; }