1. 程式人生 > 其它 >動態規劃 :P1063[NOIP2006 提高組] 能量項鍊 區間DP

動態規劃 :P1063[NOIP2006 提高組] 能量項鍊 區間DP

P1063[NOIP2006 提高組] 能量項鍊

 

 

 

 思路與分析:

  這顯然是一個環形的區間DP問題,與環形石子合併,這題具體可以看我的做法:動態規劃:洛谷P1880[NOI1995] 石子合併 區間DP 字首和 - 朱朱成 - 部落格園 (cnblogs.com)是一樣的,我們可以把n個珠子拉成2n個,環形拉成鏈狀的,就不具體狀態轉移方程的推導過程,狀態轉移方程:

dp[l][r] = max(dp[l][r], s[l]* s[r+1] * s[k+1] + dp[l][k] + dp[k + 1][r]); k是在l和r區間中的某一個端點,相當於把區間割成兩端,算出最優解,再合併算出最優解,經典的區間DP,這題唯一需要注意的是每次新得到的能量是s[l]*s[k+1]*s[r+1],注意有一個r+1,所以最好把環形珠子拉成2n+1,這樣2n的後面是第一個,不用特判.   上程式碼:
 1
#include<iostream> 2 #include<cmath> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 #include<string> 7 using namespace std; 8 const int maxn = 210; 9 int s[maxn]; 10 int dp[maxn][maxn]; 11 int main() 12 { 13 int n; 14 cin>>n; 15
for (int i = 1; i <= n; ++i) 16 { 17 cin>>s[i]; 18 s[i + n]= s[i]; 19 } 20 s[2 * n + 1] = s[1]; 21 for (int len = 2; len <= n; ++len) 22 { 23 for (int l = 1; l + len - 1 <= 2 * n; ++l) 24 { 25 int r = l + len - 1; 26 for
(int k = l; k < r; ++k) 27 { 28 dp[l][r] = max(dp[l][r], s[l]* s[r+1] * s[k+1] + dp[l][k] + dp[k + 1][r]); 29 } 30 } 31 } 32 int ans = -0x7fffffff; 33 for (int i = 1; i <= n; ++i) 34 { 35 ans = max(ans, dp[i][i + n - 1]); 36 } 37 cout << ans; 38 return 0; 39 40 }