題目描述: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(E≤2.1×(10)9),爲一個最優聚合順序所釋放的總能量。code
in:htm
4
2 3 5 10blog
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; }