light oj 1031(区间dp+博弈)

这个题目后面的套路跟石子归并写的差不多,然而这里存在一个小的博弈,就是每次取得最优,dp[i][j]
表示在区间i~j上A比B多的分数值,由于二者都采取最优策略,故可以枚举i~j之间的的数k,取子区间i~k和k+1~j中的最大值(子区间的最大值表示B比A多的分数,因为A取完之后就要改B取了,也是最优的策略),
动态转移方程式为dp[i][j]=max(dp[i][j],max((sum[k]-sum[i-1]-dp[k+1][j]),(sum[j]-sum[k]-dp[i][k])));

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
int dp[105][105];
int sum[105];
int T,n,a;
int main()
{
    cin>>T;
    int kb=1;
    while(T--)
    {

        cin>>n;
        memset(dp,0,sizeof(dp));
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            cin>>a;
            sum[i]=sum[i-1]+a;
            dp[i][i]=a;
        }

        for(int l=1;l<=n;l++)
        {
            for(int i=1;i+l-1<=n;i++)
            {
                int j=i+l-1;
                dp[i][j]=sum[j]-sum[i-1];
                if(i!=j)
                    for(int k=i;k<j;k++)
                {
                    dp[i][j]=max(dp[i][j],max((sum[k]-sum[i-1]-dp[k+1][j]),(sum[j]-sum[k]-dp[i][k])));
                }
            }
        }
          printf("Case %d: %d\n",kb++,dp[1][n]);
    }
    return 0;
}

你可能感兴趣的:(dp,区间DP)