zoukankan      html  css  js  c++  java
  • leetcode 1000. 合并石头的最低成本(区间dp)

    题意:

    有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头。

    每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的总数。

    找出把所有石头合并成一堆的最低成本。如果不可能,返回 -1 。

    示例 1:

    输入:stones = [3,2,4,1], K = 2
    输出:20
    解释:
    从 [3, 2, 4, 1] 开始。
    合并 [3, 2],成本为 5,剩下 [5, 4, 1]。
    合并 [4, 1],成本为 5,剩下 [5, 5]。
    合并 [5, 5],成本为 10,剩下 [10]。
    总成本 20,这是可能的最小值。

    示例 2:

    输入:stones = [3,2,4,1], K = 3
    输出:-1
    解释:任何合并操作后,都会剩下 2 堆,我们无法再进行合并。所以这项任务是不可能完成的。

    示例 3:

    输入:stones = [3,5,1,2,6], K = 3
    输出:25
    解释:
    从 [3, 5, 1, 2, 6] 开始。
    合并 [5, 1, 2],成本为 8,剩下 [3, 8, 6]。
    合并 [3, 8, 6],成本为 17,剩下 [17]。
    总成本 25,这是可能的最小值。

    提示:

    • 1 <= stones.length <= 30
    • 2 <= K <= 30
    • 1 <= stones[i] <= 100

    思路:

    首先有解的条件为(n-1)%(K-1)==0

    dp[i][j][k]表示把 第i堆石头到第j堆石头合并为k堆的最小代价(初始化dp[i][i][1]=0,显然,在执行过程中dp[i][j][j-i+1]都为0)

    我们可以枚举中间点m,把左边分为k-1堆,把右边分为1堆

    那么我们有: dp[i][j][k] = min(dp[i][j][k], dp[i][m][k-1] + dp[m+1][j][1])

    为什么不能是左边k-2堆,右边2堆呢?考虑右边合并为两堆,那么我们可以找一个点,划到左边,就还是左边k-1堆,右边1堆啦,所以其他所有的情况实际上都已经被 左边k-1堆,右边1堆覆盖了。

    还有一个方程就是dp[i][j][1] = dp[i][j][K] + sum[j] - sum[i-1],注意是大写的K,就是说如果有K堆了,那么我们可以把它们合并为一堆,代价为这些石头的总和。

     1 class Solution {
     2 public:
     3     int dp[50][50][50],pre[50];
     4     int mergeStones(vector<int>& stones, int K) {
     5         int n=stones.size();
     6         if((n-K)%(K-1))return -1;
     7         memset(dp,0x3f,sizeof(dp));
     8         for(int i=1;i<=n;i++){
     9             dp[i][i][1]=0;
    10             pre[i]=pre[i-1]+stones[i-1];
    11         }
    12         for(int len=2;len<=n;len++){
    13             for(int i=1;i+len-1<=n;i++){
    14                 int j=i+len-1;
    15                 for(int m=i;m<j;m++){
    16                     for(int k=2;k<=len;k++){
    17                         dp[i][j][k]=min(dp[i][j][k],dp[i][m][k-1]+dp[m+1][j][1]);
    18                     }
    19                 }
    20                 dp[i][j][1]=min(dp[i][j][1],dp[i][j][K]+pre[j]-pre[i-1]); //如果dp[l][r][K]不存在,那么也就是说明不能把[l,r]这一段区间合成一段
    21             }
    22         }
    23         return dp[1][n][1];
    24     }
    25 };
    View Code
  • 相关阅读:
    msvc交叉编译:使用vcvarsall.bat设置命令行编译环境
    DDOS到底是什么,怎么预防,看看就明白了
    服务器安全检测和防御技术
    YApi导入swagger生成的接口
    Springboot swagger2 导出api文档
    使用Swagger2Markup归档swagger生成的API文档
    springboot + swagger2 生成api文档
    swagger2 导出离线Word/PDF/HTML文档
    Swagger使用总结
    springboot配置swagger-rest文档
  • 原文地址:https://www.cnblogs.com/ljy08163268/p/11784291.html
Copyright © 2011-2022 走看看