根据寒神题解 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]; } };