• 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
  • 相关阅读:
    VS2010 自动跳过代码现象
    Reverse Linked List II 【纠结逆序!!!】
    Intersection of Two Linked Lists
    Linked List Cycle II
    Remove Nth Node From End of List 【另一个技巧,指针的指针】
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Remove Duplicates from Sorted List
    Linked List Cycle
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/ljy08163268/p/11784291.html
Copyright © 2020-2023  润新知