题目描述
小A想把他满屋子的书整理一下。书本分成若干堆。每一堆的书本都有质量w和价值v。小A的任务是将所有书合成一堆。因为小A认为合并i,j两堆的书所需要的力为w[i]-v[i]+w[j]-v[j]。合并后的书堆的质量和价值均为合并前两堆书的质量和价值的总和。也就是说,合并i,j两堆的书后,w=w[i]+w[j],v=v[i]+v[j]。合并只能在相邻两堆书本间进行。书本合并前后,位置不变。如果将1,2,3中的1,2进行合并,那么合并结果为3,3,再将3,3合并为6(1,2,3,6指质量)。请你帮他计算最少需要花费多少力气。
输入格式
第一行是一个整数n(2≤n≤400);
第二行至第n+1行,每行两个整数w和v(0<V<W≤1000)。
输出格式
仅一行,只有一个整数,表示花费的最少力气。
输入样例
3
6 5
9 7
11 2
输出样例
15
题解
区间dp水题。因为只能合并相邻两堆,所以直接套模板就行了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> #define MAXN 401 using namespace std; int n; int w[MAXN], v[MAXN]; int f[MAXN][MAXN]; int sw[MAXN][MAXN], sv[MAXN][MAXN]; int main() { cin >> n; for(register int i = 1; i <= n; i++) { cin >> w[i] >> v[i]; sw[i][i] = w[i]; sv[i][i] = v[i]; } for(register int i = 1; i <= n; i++) { for(register int j = i + 1; j <= n; j++) { sw[i][j] = sw[i][j - 1] + w[j]; sv[i][j] = sv[i][j - 1] + v[j]; } } for(register int i = n - 1; i >= 1; i--) { for(register int j = i + 1, m = 1000000000; j <= n; j++, m = 1000000000) { for(register int k = i; k < j; k++) { m = min(m, f[i][k] + f[k + 1][j] + sw[i][j] - sv[i][j]); } f[i][j] = m; } } cout << f[1][n]; return 0; }