环形石子合并
题意
将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。
规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:
选择一种合并石子的方案,使得做 n−1 次合并得分总和最大。
选择一种合并石子的方案,使得做 n−1 次合并得分总和最小。
思路
将 n 堆石子按下列方式摆放:1 2 3 . . . n − 1n
将一般的石子合并扩展为长度为 2∗n 的石子合并 最后求最值的时候遍历每个长度为 n 的区间即可
代码
#include <bits/stdc++.h> //#define int long long #define INF 0x3f3f3f3f #define mod 1000000007 #define endl '\n' #define rep(i, st, ed) for (int (i) = (st); (i) <= (ed);++(i)) #define pre(i, ed, st) for (int (i) = (ed); i >= (st);--(i)) using namespace std; typedef long long LL; typedef pair<int, int> PII; inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } inline int lowbit(int x) { return x & -x; } const int N = 500; int n; int a[N]; int f[N][N]; int g[N][N]; int sum[N]; void solve() { cin >> n; rep(i, 1, n) { cin >> a[i]; a[i + n] = a[i]; } rep(i, 1, 2 * n)sum[i] = sum[i - 1] + a[i]; for (int i = 2; i <= n; ++i) { // 枚举区间长度 for (int j = 1; j + i - 1 <= 2 * n; ++j) { // 枚举左端点 int l = j, r = j + i - 1; f[l][r] = INF; g[l][r] = -INF; for (int k = l; k < r; ++k) { f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + sum[r] - sum[l - 1]); g[l][r] = max(g[l][r], g[l][k] + g[k + 1][r] + sum[r] - sum[l - 1]); } } } int minn = INF, maxn = -INF; for (int i = 1; i <= n; ++i) { minn = min(minn, f[i][i + n - 1]); maxn = max(maxn, g[i][i + n - 1]); } cout << minn << endl << maxn << endl; } signed main() { // int t; cin >> t; // while (t--) solve(); return 0; }