根據寒神題解 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]; } };