• ACwing 282


    设有N堆石子排成一排,其编号为1,2,3,…,N。

    每堆石子有一定的质量,可以用一个整数来描述,现在要将这N堆石子合并成为一堆。

    每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。

    例如有4堆石子分别为 1 3 5 2, 我们可以先合并1、2堆,代价为4,得到4 5 2, 又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为4+9+11=24;

    如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22。

    问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

    输入格式

    第一行一个数N表示石子的堆数N。

    第二行N个数,表示每堆石子的质量(均不超过1000)。

    输出格式

    输出一个整数,表示最小代价。

    数据范围
    1≤ N ≤300
    输入样例:

    4
    1 3 5 2
    

    输出样例:

    22
    

    题目大意:

    输入一个n,接下来输入 n 个数,ai 表示合并第 i 个石子的质量,你需要将这些石子合并成一堆,每次只能选择相邻的两堆进行合并,合并的代价是两堆石子质量之和,你需要找出一种方式使得合并完的代价最小,并输出这个代价。

    解题思路:

    经典区间dp问题,从两方面分析这个问题:

    • 状态表示: 用两维去表示状态,区间问题一般都可以这样表示,f(i, j) 表示从第 i 堆石子合并到第 j 堆石子所需代价,而这道题的属性是最小值,所以用f(i, j) 表示从第 i 堆合并到第 j 堆的最小代价。
    • 状态计算: 看看如何划分这个集合,f[i][j] 可以从什么状态转移过来呢,第一重循环可以枚举长度len,从1 -> n 第二重枚举一个起点,i到i + len - 1 ,考虑最后一次合并,他一定是将两堆石子合并成一堆,所以第三重循环可以枚举分割点k ,所以每次合并的代价一定是max(f[l][r], f[l][k] + f[k + 1][r] + (sum[r] - sum[l - 1])) sum为前缀和数组,因为这次合并的代价要加上l - r 的总和,维护一个前缀和可以O1 时间去得到sum[l, r], k 的范围是i -> j - 1 ,因为至少要有一堆,以k为分界点,最后输出f(1, n) 即可。

    Code:

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    const int N = 310;
    
    int n;
    int s[N]; 
    int f[N][N];
    
    int main()
    {
        cin >> n;
        
        for (int i = 1; i <= n; i ++)
        {
            int x;
            cin >> x;
            s[i] = s[i - 1] + x;//维护一个前缀和
        }
        
        for (int len = 2; len <= n; len ++)//长度是1的代价一定是0,所以不必从1开始枚举
            for (int i = 1; i + len - 1 <= n; i ++)
            {
                int l = i, r = i + len - 1;
                
                f[l][r] = 0x3f3f3f3f;//起初这堆的代价是不知道的,初始化成一个非常大的值即可
                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]);
            }
            
        cout << f[1][n] << endl;
        
        return 0;
    }
    
  • 相关阅读:
    我的日常笔记
    html元素是如何占据空间和定位的
    jdbc和数据库的应用
    java笔记之String的应用
    java笔记之静态修饰附和单例设计模式
    java笔记
    本人对于JavaScript的一些总结
    JavaScript 轮播图
    h5简单布局练习
    有一个八位数,个位数+十位数+百位数+千位数一直加到千万位数的和除以7能等于0.。。。
  • 原文地址:https://www.cnblogs.com/Hayasaka/p/14294129.html
Copyright © 2020-2023  润新知