vj2006(区间dp)

来源:互联网 发布:abp zero 源码 编辑:程序博客网 时间:2024/05/18 01:48

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

题意:

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

题解:

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

那么定义这样的状态: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+5int 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;}


0 0
原创粉丝点击