Codevs 1048 石子合并
题目描述 Description
有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。
输入描述 Input Description
第一行一个整数n(n<=100)
第二行n个整数w1,w2...wn (wi <= 100)
输出描述 Output Description
一个整数表示最小合并代价
样例输入 Sample Input
4
4 1 1 4
样例输出 Sample Output
18
分析——区间dp
Dp啊经典题目吧
Dp[i][j]表示将i到j堆石子全部合并所花费的最小代价
Sum[i][j]表示 i到j堆石子数的和
测试数据
|
1 |
2 |
3 |
4 |
1 |
/ |
/ |
/ |
/ |
2 |
5 |
/ |
/ |
/ |
3 |
8 |
2 |
/ |
/ |
4 |
18 |
8 |
5 |
/ |
K为中间点枚举两边的石子堆,若石子堆还未被合并过加0
当前代价为最小之前的合并代价+此时i到j堆的石子数的和
即dp[i][j]=min(dp[i][j],dp[k][j]+a[j][i]+dp[i][k+1]);
1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<cmath>
6 #include<algorithm>
7 #define maxn 2147483647
8
9 using namespace std;
10
11 int n,a[101][101],dp[101][101];
12 int main()
13 {
14 cin>>n;
15 for(int i=1;i<=n;i++)
16 {
17 scanf("%d",&a[i][i]);
18 dp[i][i]=0;
19 for(int j=1;j<i;j++)a[j][i]=a[j][i-1]+a[i][i];
20 }
21 for(int i=2;i<=n;i++)
22 {
23 for(int j=i-1;j>=1;j--)
24 {
25 dp[i][j]=maxn;
26 if(j==i-1)dp[i][j]=a[j][i];
27 for(int k=j;k<i;k++)
28 dp[i][j]=min(dp[i][j],dp[k][j]+a[j][i]+dp[i][k+1]);
29 }
30 }
31 cout<<dp[n][1];
32 system("pause");
33 return 0;
34 }