将 n 堆石子排放在一条直线上,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:
选择一种合并石子的方案,使得做 n−1 次合并得分总和最小。
输入格式:
输入第一行一个整数 n,表示有 n 堆石子(n<=200)。
第二行 n 个整数,表示每堆石子的数量(每堆石子<1000)。
输出格式:
输出一行为合并得分总和最小值,
输入样例:
6
5 9 3 4 2 6
输出样例:
73
代码
#include <iostream>
using namespace std;
#define MAXN 20000 + 10
int t, n, a[MAXN];
double ans = 0;
void work(int k)
{
int tmp = a[k - 1] + a[k];
ans += tmp;
for (int i = k; i < t - 1; i++)
a[i] = a[i + 1];
t--;
int j = 0;
for (j = k - 1; j > 0 && a[j - 1] < tmp; j--)
a[j] = a[j - 1];
a[j] = tmp;
while (j >= 2 && a[j] >= a[j - 2])
{
int d = t - j;
work(j - 1);
j = t - d;
}
}
int main()
{
scanf("%d", &n);
ans = 0;
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
t = 1;
for (int i = 1; i < n; i++)
{
a[t++] = a[i];
while (t >= 3 && a[t - 3] <= a[t - 1])
work(t - 2);
}
while (t > 1)
work(t - 1);
printf("%.0lf\n", ans);
return 0;
}