洛谷P1063能量項鍊(區間dp)

題目描述:html

給定一串序列x[],其中的每個Xi看做看做一顆珠子,每一個珠子包含兩個參數,head和tail,前一顆的tail值是後一個的head值,珠子呈現環形(是一條項鍊),因此最後一顆的tail是第一個珠子的head.當tail遇到對應的head時會放出node

Xi.head*Xi.tail*X++i.head,以後這兩顆相鄰的珠子會變成新的一顆Xp,它的參數爲Xp.head=Xi.head,Xp.tail=X++i.tail,問整條項鍊合併到只剩下一顆時所能產生的最大能量.c++

題目連接:P1063算法

至於珠子的順序,你能夠這樣肯定:將項鍊放到桌面上,不要出現交叉,隨意指定第一顆珠子,而後按順時針方向肯定其餘珠子的順序。spa

輸出格式

一個正整數E(E≤2.1×(10)9)E(E≤2.1 \times (10)^9)E(E2.1×(10)9),爲一個最優聚合順序所釋放的總能量。code

in:htm

4
2 3 5 10
blog

out:ci

710get

思路:區間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;
}
相關文章
相關標籤/搜索