最小代价树(0404)
Time limit(ms): 1000
Memory limit(kb): 65535
Submission: 49
Accepted: 18
Accepted
区间dp经典题
以下方法称为最小代价的字母树:给定一正整数序列,例如:4,1,2,3,在不改变数的位置的条件下把它们相加,并且用括号来标记每一次加法所得到的和。
例如:((4+1)+ (2+3))=((5)+(5))=10。除去原数不4,1,2,3之外,其余都为中间结果,如5,5,10,将中间结果相加,得到:5+5+10= 20,那么数20称为此数列的一个代价,若得到另一种算法:(4+((1+2)+3))=(4+((3)+3))=(4+(6))=10,数列的另一个代价为:3+6+10=19。若给出N个数,可加N-1对括号,求出此数列的最小代价。
注:结果范围不超出longint.
例如:((4+1)+ (2+3))=((5)+(5))=10。除去原数不4,1,2,3之外,其余都为中间结果,如5,5,10,将中间结果相加,得到:5+5+10= 20,那么数20称为此数列的一个代价,若得到另一种算法:(4+((1+2)+3))=(4+((3)+3))=(4+(6))=10,数列的另一个代价为:3+6+10=19。若给出N个数,可加N-1对括号,求出此数列的最小代价。
注:结果范围不超出longint.
Description
第一行为数N(1≤N≤200),第二行为N个正整数,整数之间用空格隔开。
Input
输出仅一行,即为最少代价值。
Output
1
2
|
4
4 1 2 3
|
Sample Input
1
|
19
|
/*
* 1. 先求每两个数合并的最小值
* 2. 再求每三个合并的最小值 由1中推出的结果 可推出 f(i,j) = min(f[i][k] + f[k+1][j] + sum[i][k] + sum[i][k] + sum[k+1][j])
3. 重复 一直到求出n个数合并的最小值
*/
#include "iostream"
#include "cstring"
#include "algorithm"
using namespace std;
int main() {
int n;
int a[201];
int dp[201][201];
int sum[201][201];
cin >> n;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[i][i] = a[i];
}
for(int l=2;l<=n;l++)
for(int i=1;i<=n-l+1;i++)
{
int j = i + l - 1;
dp[i][j] = 1 << 30;
for (int k = i; k < j; k++) {
sum[i][j] = sum[i][k] + sum[k+1][j];
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[i][j]);
}
}
cout << dp[1][n] << endl;
return 0;
}