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