LeetCode 1000. Minimum Cost to Merge Stones (区间 DP)

根据寒神题解 https://leetcode.com/problems/minimum-cost-to-merge-stones/discuss/247567/JavaC%2B%2BPython-DP

题意:

每次可以把连续 K 堆石头合成一堆,花费是 K 堆之和,问最小花费多少可以把全部石头合成 1 堆。不能做到的话,返回 -1。

题解:

因为,每次把 K 堆变成 1 堆,也就是说每次都减去 K-1 堆,最后剩下 1 堆,所以只有在  (n - 1) % (K - 1) == 0  才可以合成 1 堆。

 

 dp[i][j] 表示  stones[i..j]  尽可能合并之后,花费的最小值。

 

然后枚举第i个石头和前几个石头合成了一堆。 只有长度为  1 + (K-1)*x  时才能合成一堆,所以枚举长度每次加  K - 1 。

 

class Solution {
public:
    int mergeStones(vector<int>& stones, int K) {
        int n = stones.size();
        if ((n-1) % (K-1)) return -1;
        vector<int> prefix(n + 1);
        for (int i = 1; i <= n; i++) prefix[i] = prefix[i-1] + stones[i - 1];
        vector<vector<int>> dp(n, vector<int>(n, 0));
        // 当j-i < K 时不需要合并 所以值为 0
        for (int l = K - 1; l < n; l++) {
            for (int s = 0; s + l < n; s++) {
                int e = s + l;
                dp[s][e] = INT_MAX;
                for (int m = s; m < e; m += K - 1) {
                    dp[s][e] = min(dp[s][e], dp[s][m] + dp[m + 1][e]);
                }
                // l % (K - 1) == 0 刚好可以合成一堆
                // 因为枚举的是左边合成一堆,所以左右相加之后一定大于一堆,不是最简状态
                // 所以需要再次合并 合并需要的值就是区间和
                if (l % (K - 1) == 0) {
                    dp[s][e] += prefix[e + 1] - prefix[s];
                }
            }
        }
        return dp[0][n - 1];
    }
};

 

posted @ 2020-04-17 00:25  我不吃饼干呀  阅读(230)  评论(0编辑  收藏  举报