vj2006(区间dp)

很好的一题,一些细节要注意

题意:

有很多个珍珠,每个珍珠都有头和尾,两个珍珠合并之后所能得到的能量为:一个珍珠的头*第一个珍珠的尾*第二个珍珠的尾。问如何合并珍珠能够让能量最大

题解:

其实这题可以化简成求去某个数,得到的价值为这个数乘以左右相邻的数。

那么定义这样的状态:dp[i][j]代表“开区间”(i,j)能得到的最大能量。注意枚举长度时要,长度要加1,这个小细节很重要。采用循环数组,枚举结果区间的长度也要+1。具体看代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
typedef long long lld;
#define oo 0x3f3f3f3f
#define maxn 210+5
int dp[maxn][maxn];
int a[maxn];

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i+n]=a[i];
        }
        memset(dp,0,sizeof dp);
        for(int i=1;i+2<=2*n;i++)
            dp[i][i+2]=a[i]*a[i+1]*a[i+2];
        for(int L=4;L<=n+1;L++)
        {
            for(int i=1;i+L-1<=2*n;i++)
            {
                int j=i+L-1;
                dp[i][j]=max(dp[i+1][j]+a[i]*a[i+1]*a[j],dp[i][j-1]+a[i]*a[j-1]*a[j]);
                for(int k=i+2;k<=j-2;k++)
                    dp[i][j]=max(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[k]*a[j]);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,dp[i][i+n]);
        printf("%d\n",ans);
    }
	return 0;
}



你可能感兴趣的:(dp,VJ)