石子合并

题目描述 

将n堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数n及每堆的石子数,并进行如下计算:
  1. 选择一种合并石子的方案,使得做n-1次合并得分总和最大。
  2. 选择一种合并石子的方案,使得做n-1次合并得分总和最小。

输入描述:

输入第一行一个整数n,表示有n堆石子。
第二行n个整数,表示每堆石子的数量。

输出描述:

第一行为合并得分总和最小值,
第二行为合并得分总和最大值。

输入

4
4 5 9 4

输出

43
54
#include<bits/stdc++.h>
using namespace std;
const int N = 4e2 + 7;
int a[N], n;
int mi[N][N], mx[N][N], sum[N];
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i], a[i + n] = a[i];
    for (int i = 1; i <= 2 * n; i++) sum[i] = sum[i - 1] + a[i];
    memset(mi, 0x3f, sizeof(mi));
    memset(mx, 0, sizeof(mx));
    for (int i = 1; i <= 2 * n; i++) mi[i][i] = 0, mx[i][i] = 0;
    for (int len = 2; len <= n; len++) {
        for (int l = 1; l <= 2 * n - len + 1; l++) {
            int r = l + len - 1;//[l, r]
            for (int k = l; k < r; k++) {
                mi[l][r] = min(mi[l][r], mi[l][k] + mi[k + 1][r] + sum[r] - sum[l - 1]);
                mx[l][r] = max(mx[l][r], mx[l][k] + mx[k + 1][r] + sum[r] - sum[l - 1]);
            }
        }
    }
    int least = 0x3f3f3f3f, most = 0;
    for (int i = 1; i <= n; i++) {
        least = min(least, mi[i][i + n - 1]);
        most = max(most, mx[i][n + i - 1]);
    }
    cout << least << endl;
    cout << most << endl;
    return 0;
}
posted @ 2020-07-17 09:58  HighLights  阅读(166)  评论(0)    收藏  举报