动态规划 :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 }