1. 程式人生 > 其它 >1570:【例 2】能量項鍊

1570:【例 2】能量項鍊

原題來自:NOIP 2006

在 Mars 星球上,每個 Mars 人都隨身佩帶著一串能量項鍊。在項鍊上有 $N$ 顆能量珠。能量珠是一顆有頭標記和尾標記的珠子,這些標記對應著某個正整數。並且,對於相鄰的兩顆珠子,前一顆珠子的尾標記必定等於後一顆珠子的頭標記。因為只有這樣,通過吸盤——Mars 人吸收能量的器官的作用,這兩顆珠子才能聚合成一顆珠子,同時釋放出可被吸盤吸收的能量。如果一顆能量珠頭標記為 $m$,尾標記為 $r$,後一顆能量珠頭標記為 $r$,尾標記為 $n$,則聚合後釋放出 $m×r×n\;$ Mars單位的能量,新珠子頭標記為 $m$,尾標記為 $n$。

當需要時,Mars 人就用吸盤夾住相鄰的兩顆珠子,通過聚合得到能量,直到項鍊上只剩下一顆珠子為止。顯然,不同的聚合順序得到的總能量是不一樣的。請設計一個聚合順序使得一串珠子聚合後釋放出的總能量最大。

例如,設 $N=4$,四顆珠子頭標記與尾標記分別為 $(2,3),(3,5),(5,10),(10,2)$。我們用記號 $⨂$ 表示兩顆珠子的聚合操作,($j⨂k$) 表示 $j,k$ 兩顆珠子聚合後釋放出的能量,則$4,1$兩顆珠子聚合後所釋放的能量為$(4⨂1)=10×2×3=60$,這一串項鍊可以得到最優值的一個聚合順序所釋放出的總能量為$(((4⨂1)⨂2)⨂3)= 10×2×3+10×3×5+10×5×10=710$

現在給你一串項鍊,項鍊上有 $n$ 顆珠子,相鄰兩顆珠子可以合併成一個,合併同時會放出一定的能量,不同珠子合併放出能量不相同,請問按怎樣的次序合併才能使得釋放的能量最多?

【輸入】

第一行一個正整數 $n$

第二行 $n$ 個不超過 $1000$ 的正整數,第 $i(1≤i≤n)$ 個數為第 $i$ 顆珠子的頭標記,當 $i\neq n$ 時第 $i$ 顆珠子的尾標記等於第 $i+1$ 顆珠子的頭標記,當 $i=n$ 時第 $i$ 顆珠子的尾標記等於第 $1$ 顆珠子的頭標記。

至於珠子的順序,你可以這樣確定:將項鍊放在桌面上,不要出現交叉,隨機指定一顆珠子為第一顆珠子,按順時針確定其它珠子的順序。

【輸出】

輸出只有一行,一個不超過 $2.1×10^9$ 的正整數,表示最優聚合順序所釋放的能量。

【輸入樣例】

4
2 3 5 10

【輸出樣例】

710

【提示】

資料範圍與提示:

對於 100% 的資料,$4≤n≤100$。

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;
const int N = 300;
int a[N];
int n;

int f[N][N];

int main()
{
    scanf("%d",&n);
    for(int i = 1 ;i <= n; i++)
    {
        scanf("%d", &a[i]);
        a[i + n] = a[i]; 
    }
    
    for(int len = 3; len <= n * 2; len ++)
    {
        for(int l = 1; l + len - 1 <= n * 2; l++)
        {
            int r = l + len - 1;
            for(int k = l + 1; k < r; k++)
            {
                f[l][r] = max(f[l][r], f[l][k] + f[k][r] + a[l] * a[r] * a[k]);
            }
        }
    }
    int res = 0;
    for(int l = 1; l + n <= n * 2; l++)
    {
        res = max(res, f[l][l + n]);
    }
    printf("%d", res);
    return 0;
}