区间dp:合并石子

题目链接:https://www.acwing.com/problem/content/284/
题意:设有N堆石子排成一排,其编号为1,2,3,…,N。
每堆石子有一定的质量,可以用一个整数来描述,现在要将这N堆石子合并成为一堆。
每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。
找出一种合理的方法,使总的代价最小,输出最小代价。
数据范围
1≤N≤300
输入样例:
4
1 3 5 2
输出样例:
22
思路:时间复杂度O(n^3)

  • 状态表示:1.集合:f[i , j] 表示所有第i ~ j堆石子的合并方式; 2.属性:寻找这些方式中代价的最小值min
  • 状态计算:对于计算一个区间[i , j]的最小消耗, 我们可以将其看成把两个小区间[i , k]和[k , j]合并的最小消耗(k是从i到j进行枚举),即f[i , j] = min(f[i , j] , f[i , k] + f[k , j] + s[j] - s[i - 1])。
    代码实现:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN=305;
int n,s[MAXN];
int f[MAXN][MAXN];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++ )
        scanf("%d", &s[i]);
    for(int i = 1; i <= n; i ++ )
        s[i] += s[i - 1];
    for(int len = 2; len <= n; len ++ ){
        for(int i = 1; i + len - 1 <= n; i ++ ){
            int l = i, r = i + len - 1;
            f[l][r] = INF;
            for(int k = l; k < r; k ++ )
                f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
        }
    }
    printf("%d\n",f[1][n]);
    return 0;
}

发布了61 篇原创文章 · 获赞 0 · 访问量 977

猜你喜欢

转载自blog.csdn.net/Satur9/article/details/104035143