1. 程式人生 > 其它 >動態規劃:洛谷P1880[NOI1995] 石子合併 區間DP 字首和

動態規劃:洛谷P1880[NOI1995] 石子合併 區間DP 字首和

P1880[NOI1995] 石子合併

 

     相較於P1775 石子合併(弱化版) - 洛谷 | 電腦科學教育新生態 (luogu.com.cn),洛谷P1775,這題就是變成了環形石子,我們可以用把環形拉成鏈,n->2n,這樣從1->n的每一個為元素起點,長度為n,得到的序列,就是環形的每一個元素為起點的每一種可能,然後像P1775一樣的方法區間DP,具體可以看我的題解,講的非常清楚:動態規劃:P1775石子合併(弱化版)區間DP、字首和 - 朱朱成 - 部落格園 (cnblogs.com),最後有所區別的是ans並非dp[1][n],而要用一個for迴圈遍歷dp[i][i+n]的最優解,注意這裡求最大值和最小值,需要建立兩個DP陣列,區別就是max和min,還有初始值求max要初始化為0,求Min初始化為INT_MAX。

    上程式碼:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<string>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn = 210;
 8 int dp1[maxn][maxn];
 9 int dp2[maxn][maxn];
10 int a[maxn];
11 int pre[maxn];
12 const int inf = 0x7fffffff
; 13 int main() 14 { 15 int n; 16 cin >> n; 17 for (int i = 1; i <= n; ++i) 18 { 19 cin >> a[i]; 20 a[i + n] = a[i]; 21 } 22 for (int i = 1; i <= 2 * n; ++i) 23 { 24 pre[i] = pre[i - 1] + a[i]; 25 } 26 for (int len = 2; len <= n; ++len)
27 { 28 for (int l = 1; l + len - 1 <= 2*n; ++l) 29 { 30 int r = l + len - 1; 31 dp2[l][r] = inf;//算最小值的時候給一個大值 便於計算最小值 32 for (int k = l; k < r; ++k) 33 { 34 dp1[l][r] = max(dp1[l][r], dp1[l][k] + dp1[k + 1][r] + pre[r] - pre[l - 1]); 35 dp2[l][r] = min(dp2[l][r], dp2[l][k] + dp2[k + 1][r] + pre[r] - pre[l - 1]); 36 } 37 } 38 39 } 40 int ans1 = inf, ans2 = -inf; 41 for (int i = 1; i <= n; ++i) 42 { 43 ans1 = min(dp2[i][n + i - 1], ans1); 44 ans2 = max(dp1[i][n + i - 1], ans2); 45 } 46 cout << ans1 << endl << ans2; 47 return 0; 48 49 }