[codevs1048]石子归并

来源:互联网 发布:股票数据实时抓取 编辑:程序博客网 时间:2024/06/06 15:45

题目描述 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
    
  
发现每合并两堆已合并石子的代价,为每已合并堆中所有石子重量之和;
如先合并1—2堆、3—4堆石子
再将两个新堆合并时,代价为w[1]+w[2]+w[3]+w[4]
而1—2堆石子合并代价为w[1]+w[2]
3—4堆石子合并代价为w[3]+w[4],
故总代价为w[1]+w[2]+w[3]+w[4]+w[1]+w[2]+w[3]+w[4] = 20
显然不是最优解
  

发现在合并第i—j堆石子时,有合并i—k、k+1—j两堆石子共k(k = j - i)种选择
由此可知我们在求dp[i][j]//dp[i][j]为合并第i到第j堆石子的最小代价
时,必须已知其中任两堆石子i—k、k+1—j的最优合并代价
股采用顺推j,逆推i
枚举k为断点
预处理cost[i][j]为一次合并i—j堆石子(无论先前合并顺序)的代价
递推式:dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j] + cost[i][j]);

#include<iostream>#include<cstring>using namespace std;const int MAXN = 2000 + 5;int w[MAXN],dp[MAXN][MAXN],cost[MAXN][MAXN];int n;int main(){    cin >> n;    for(int i = 1;i <= n;i ++)    {        cin >> w[i];    }    memset(dp,0x3f,sizeof(dp));    for(int i = 1;i <= n;i ++)    for(int j = i;j <= n;j ++)    {        if(i == j)dp[i][j] = 0;        cost[i][j] = cost[i][j - 1] + w[j];    }    for(int j = 2;j <= n;j ++)    for(int i = j - 1;i >= 1;i --)    for(int k = i;k < j;k ++)    {        dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j] + cost[i][j]);    }    cout << dp[1][n];    return 0;}

结:感觉dp型题目的问题有两个
一个是递推式,一个是递推过程
怎样保证在已知需要前提的条件下推出结果
也是这题比较难的部分吧

0 0
原创粉丝点击