洛谷P1063能量项链(区间dp)

题目描述:

给定一串序列x[],其中的每一个Xi看作看作一颗珠子,每个珠子包含两个参数,head和tail,前一颗的tail值是后一个的head值,珠子呈现环形(是一条项链),所以最后一颗的tail是第一个珠子的head.当tail遇到对应的head时会放出

Xi.head*Xi.tail*X++i.head,之后这两颗相邻的珠子会变成新的一颗Xp,它的参数为Xp.head=Xi.head,Xp.tail=X++i.tail,问整条项链合并到只剩下一颗时所能产生的最大能量.

题目链接:P1063

至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出格式

一个正整数E(E≤2.1×(10)9)E(E≤2.1 \times (10)^9)E(E2.1×(10)9),为一个最优聚合顺序所释放的总能量。

in:

4
2 3 5 10

out:

710

思路:区间dp,以小区间来作为最优子结构来计算大区间,整个题目的解法等价于找1~E中从哪一个最开始先合并,我们以dp[i][j]表示合并区间i到j的最优解,在i到j中选取k开始合并的状态转移方程为:dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i].h*a[j].t*a[i+k].t)

那么算法大体就定下来了O(n^3)的思路

#include <bits/stdc++.h>
using namespace std;
struct node//存珠子
{
    int h;
    int t;
} e[1005];
int n;
int dp[205][205];
int total;
int main()
{
    cin>>n;
    for(int i=1; i<n; i++)
    {
        int x;
        cin>>x;
        if(i==1)
        {
            int y;
            cin>>y;
            e[i].h=x;
            e[i].t=y;
            continue;
        }
        e[i].h=e[i-1].t;
        e[i].t=x;
        if(i==n-1)
        {
            e[n].h=e[n-1].t;
            e[n].t=e[1].h;
        }
    }//输入,第一个和最后一个做了特判
    for(int i=1; i<n; i++)
        e[i+n]=e[i];//这一步很关键,相当于拆环,把整段序列在往尾部接上一次,以达到环形
    for(int i=1; i<=n; i++)
        for(int j=1; j<2*n-i; j++)
            for(int k=j; k<i+j; k++)
                dp[j][j+i]=max(dp[j][j+i],dp[j][k]+dp[k+1][j+i]+e[j].h*e[k].t*e[i+j].t);
    for(int i=1;i<=n;i++)
              total=max(total,dp[i][i+n-1]);
    cout<<total;

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/iloveysm/p/12319245.html