NOIP模拟 Game 【博弈论】【动态规划】

来源:互联网 发布:网络英语教育 编辑:程序博客网 时间:2024/06/05 21:17

题目大意:

有n个物品排成一排,从左往右第i个价值为a[i],有两个人从左往右轮流取物品。第一个人可以拿一或两个物品。如果前一个人拿了k个,下一个人只能拿k或k+1个。如果剩下的物品不够拿,就结束。问如果大家都采取最优策略,那么先手拿的物品的价值最多能比后手多多少。(1n20000)

解题思路:

设dp[i][k]表示从第i个物品开始先手拿k个后最多能比后手多取的价值,则:
dp[i][k]=sum[i~i+k-1]+max(dp[i+k][k],dp[i+k+1][k+1])
注意到k最多取到200(20000<1+2+……+200),所以第二维只用开到200即可。
(考试时想到了k的取值范围但不知为何脑抽了……)

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<queue>#define ll long longusing namespace std;int getint(){    int i=0,f=1;char c;    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());    if(c=='-')f=-1,c=getchar();    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';    return i*f;}const int N=20005,K=205;int T,n;ll a[N],dp[N][K];int main(){    //freopen("game.in","r",stdin);    //freopen("game.out","w",stdout);    T=getint();    while(T--)    {        memset(dp,0,sizeof(dp));        memset(a,0,sizeof(a));        n=getint();        for(int i=1;i<=n;i++)            a[i]=a[i-1]+getint();        for(int i=n;i;i--)            for(int k=1;i+k-1<=n&&k<=i+1&&k<=200;k++)                dp[i][k]=a[i+k-1]-a[i-1]-max(dp[i+k][k],dp[i+k][k+1]);        /*for(int i=1;i<=n;i++)            for(int k=1;k<=n;k++)                printf("dp[%d][%d]: %d\n",i,k,dp[i][k]);*/        cout<<max(dp[1][1],dp[1][2])<<'\n';    }    return 0;}
原创粉丝点击