1048 石子归并
题目描述 Description有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。
输入描述 Input Description第一行一个整数n(n<=100)
第二行n个整数w1,w2...wn (wi <= 100)
输出描述 Output Description一个整数表示最小合并代价
样例输入 Sample Input4
4 1 1 4
样例输出 Sample Output18
一道典型的区间型dp。
我们可以设dp[i][j]表示从第i堆(包含i)到第j堆(包含j)石子的合并的最小代价。我们可以写出状态转移方程为:
dp[i][j] = min{dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]}, i <= k < j (i !+ j)
附AC代码:
1 #include<iostream> 2 #include<cmath> 3 #include<cstring> 4 using namespace std; 5 6 const int INF=1<<30; 7 const int MAXV=110; 8 9 int dp[MAXV][MAXV]; 10 int sum[MAXV]; 11 int w[MAXV]; 12 13 int main(){ 14 int n; 15 while(cin>>n){ 16 memset(sum,0,sizeof(sum)); 17 for(int i=1;i<=n;i++){ 18 cin>>w[i]; 19 sum[i]=sum[i-1]+w[i]; 20 dp[i][i]=0;//在t==2时会用到 21 } 22 for(int t=2;t<=n;t++){//表示合并的区间长度 即i~j(包括i,j) 23 for(int i=1;i<=n;i++){ 24 int j=i+t-1;//由于包含j故减一 25 int MAX=INF; 26 for(int k=i;k<j;k++){ 27 if(MAX>dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])//状态方程 28 MAX=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]; 29 } 30 dp[i][j]=MAX;//存入dp 31 } 32 } 33 cout<<dp[1][n]<<endl; 34 } 35 return 0; 36 }