zoukankan      html  css  js  c++  java
  • 台州 OJ 2793 石子归并 区间DP

    描述

     

    有n堆石子排成一条直线,每堆石子有一定的重量。现在要合并这些石子成为一堆石子,但是每次只能合并相邻的两堆。每次合并需要消耗一定的体力,该体力为所合并的两堆石子的重量之和。问最少需要多少体力才能将n堆石子合并成一堆石子?

    输入

     

    输入只包含若干组数据。每组数据第一行包含一个正整数n(2<=n<=100),表示有n堆石子。接下来一行包含n个正整数a1,a2,a3,...,an(0<ai<=100,1<=i<=n)。

    输出

     

    对应输入的数据,每行输出消耗的体力。

    dp[i][j] 表示区间 i~j 的石子合并消耗的最少体力,sum[i][j] 表示区间 i~j 的石子加起来的数量

    dp[i][j] = min(dp[i][k] + dp[k+1][j] + sum[i][j])   i <= k < j

    没有用平行四边形优化(不懂T^T)

    代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int MAX = 105;
    
    int n;
    int dp[MAX][MAX];
    int w[MAX];
    int sum[MAX];
    
    int main(){
    //    freopen("input.txt", "r", stdin);
        
        while(cin >> n){
            memset(dp, 0x3f, sizeof(dp));
            for(int i=1; i<=n; i++){
                cin >> w[i];
                dp[i][i] = 0;
                sum[i] = w[i];
            }
            
            //dp[i][j] = min(dp[i][k] + dp[k][j]) ( i <= k <= j )
            for(int len=2; len<=n; len++){
                for(int i=1; i+len-1<=n; i++){
                    int j = i + len - 1;
                    sum[i] += w[j];
                    for(int k=i; k<j; k++){
                        dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[i]);
                    }
                }
            }
            
            cout << dp[1][n] << endl;
        }
        
        return 0;
    } 

    之后在网上看了这题的解法,发现有个叫做平行四边形优化的东西,不过我实在没能看懂证明,看了个似懂非懂,就在纸上理了一下。

    石子归并问题里,w[i][j] 就是 sum[i][j]。

  • 相关阅读:
    vue-cli模拟后台数据交互
    打卡谱
    前端面试题
    ps简单切图
    常见浏览器兼容性问题与解决方案
    扯淡 测量体质公式 哈哈哈哈会不会封我号
    JAVASCRIPT 转换字符串杂记
    日记(六)
    gitshell 基础操作
    gitshell fork别人项目
  • 原文地址:https://www.cnblogs.com/lighter-blog/p/7298955.html
Copyright © 2011-2022 走看看