hdu4597(区间DP)

本文探讨使用区间动态规划(DP)解决一个竞赛难题。通过定义状态数组和状态转移方程,作者详细解释了如何计算两个区间内的最大价值。文章包含代码注释,帮助读者理解并实现解决方案。

这是区域赛的一道题目,感觉还是很难,做了好久都没想法,然后看了解题

区间dp,dp[a1][a2][b1][b2]表示在这两个区间内,先后所能获得的最大值,然后就是状态转移,有四种可能,以取a堆最左边的那个数字为例,状态转移方程如下:

dp[a1][a2][b1][b2] = max(dp[a1][a2][b1][b2],a[a1+1]+suma[a2-1]-suma[a1+1]+sumb[b2-1]-sumb[b1]-dfs(a1+1,a2,b1,b2));

数组的含义看代码注释,-法后手的东西表示后首在先手完成的情况下实现的最大价值

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>

#define N 25
#define inf 0x7fffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
int a[N],b[N];//a,b记录输入数组
int suma[N],sumb[N];//记录前i个数之后
int dp[N][N][N][N];//第一堆代表区间a1到a2,第一堆b1到b2

int dfs(int a1,int a2,int b1,int b2)
{
    if(dp[a1][a2][b1][b2] != -1) return dp[a1][a2][b1][b2];
    dp[a1][a2][b1][b2] = 0;
    if(a1+1 < a2)
        dp[a1][a2][b1][b2] = max(dp[a1][a2][b1][b2],a[a1+1]+suma[a2-1]-suma[a1+1]+sumb[b2-1]-sumb[b1]-dfs(a1+1,a2,b1,b2));
    if(a1 < a2-1)
        dp[a1][a2][b1][b2] = max(dp[a1][a2][b1][b2],a[a2-1]+suma[a2-2]-suma[a1]+sumb[b2-1]-sumb[b1]-dfs(a1,a2-1,b1,b2));
    if(b1+1 < b2)
        dp[a1][a2][b1][b2] = max(dp[a1][a2][b1][b2],b[b1+1]+suma[a2-1]-suma[a1]+sumb[b2-1]-sumb[b1+1]-dfs(a1,a2,b1+1,b2));
    if(b1 < b2-1)
        dp[a1][a2][b1][b2] = max(dp[a1][a2][b1][b2],b[b2-1]+suma[a2-1]-suma[a1]+sumb[b2-2]-sumb[b1]-dfs(a1,a2,b1,b2-1));
    return dp[a1][a2][b1][b2];
}

int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int i,j;
        suma[0] = 0;
        for(i = 1; i <= n; i++){
            scanf("%d",&a[i]);
            suma[i] = suma[i-1] + a[i];
        }
        sumb[0] = 0;
        for(i = 1; i <= n; i++)
        {
            scanf("%d",&b[i]);
            sumb[i] = sumb[i-1] + b[i];
        }
        memset(dp,-1,sizeof(dp));
        dfs(0,n+1,0,n+1);
        printf("%d\n",dp[0][n+1][0][n+1]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值