【题目描述】
将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:
1、选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。
2、选择一种合并石子的方案,使得做 n−1 次合并得分总和最小。
【输入】
输入第一行一个整数 n ,表示有 n 堆石子。
第二行 n 个整数,表示每堆石子的数量。
【输出】
输出共两行:
第一行为合并得分总和最小值,
第二行为合并得分总和最大值。
【输入样例】
4
4 5 9 4
【输出样例】
43
54
【提示】
数据范围与提示:
对于 100的数据,有1≤n≤200 。
#include<bits/stdc++.h>
using namespace std;
int n, a[405], s[405];
int b1[405][405], b2[405][405];
int q1(int l, int r) {
if (l == r) return 0;
if (b1[l][r] != -1) return b1[l][r];
int p = 1e9;
for (int i = l; i < r; i++) {
p = min(p, q1(l, i) + q1(i + 1, r) + s[r] - s[l - 1]);
}
return b1[l][r] = p;
}
int q2(int l, int r) {
if (l == r) return 0;
if (b2[l][r] != -1) return b2[l][r];
int p = 0;
for (int i = l; i < r; i++) {
p = max(p, q2(l, i) + q2(i + 1, r) + s[r] - s[l - 1]);
}
return b2[l][r] = p;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i + n] = a[i];
}
for (int i = 1; i <= n * 2; i++) {
s[i] = s[i - 1] + a[i];
}
int Min = 1e9;
memset(b1, -1, sizeof(b1));
for (int i = 1; i <= n; i++) {
int m = q1(i, i + n - 1);
Min = min(Min, m);
}
cout << Min << endl;
int Max = 0;
memset(b2, -1, sizeof(b2));
for (int i = 1; i <= n; i++) {
int m = q2(i, i + n - 1);
Max = max(Max, m);
}
cout << Max << endl;
return 0;
}