目录
题目描述
在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个程序,计算出将N堆石子合并成一堆的最小得分。
输入
第一行为一个正整数N (2≤N≤100);
以下N行,每行一个正整数,小于10000,分别表示第i堆石子的个数(1≤i≤N)。
输出
为一个正整数,即最小得分。
样例输入
7 13 7 8 16 21 4 18
样例输出
239
解释题意
给你一堆数,将数字合并成一个数,每次只能选相邻的2个数合并成新的一个数,并将新的数记为该次合并的得分
思路
这是区间背包的板子题,我们可以枚举起点与终点来确定区间范围,再使用前缀和优化
时间复杂度:O()
前置知识:前缀和
统计前N个数的和,要求下表x,y范围内的和就可以a[x]-a[y]
即:
OK,开始魔法
Code:
#include <bits/stdc++.h>
using namespace std;
int n;
int a[360]/*输入数据(后期也用于前缀和)*/, dp[360][360]/*dp数组,存储i~j范围内代价最小*/;
int main() {
cin >> n;
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++)
cin >> a[i]/*输入*/, a[i] += a[i - 1]/*前缀和计算*/;
for (int i = 1; i <= n; i++) dp[i][i] = 0;//进行从自己到自己的代价为0的设置
for (int len = 2; len <= n; len++)//枚举区间长度
for (int i = 1; i + len - 1 <= n; i++) { //枚举起点
int j = i + len - 1;//计算终点
for (int k = i; k < j; k++)//遍历区间
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + a[j] - a[i - 1]);//板子
// 和自己比较 i~j在dp中的范围 加上前缀和
}
cout << dp[1][n]/*进行输出*/;
return 0;
}