There are n piles of stones arranged in a row. The ith pile has stones[i] stones.
A move consists of merging exactly k consecutive piles into one pile, and the cost of this move is equal to the total number of stones in these k piles.
Return the minimum cost to merge all piles of stones into one pile. If it is impossible, return -1.
Example 1:
Input: stones = [3,2,4,1], k = 2
Output: 20
Explanation:
We start with [3, 2, 4, 1].
We merge [3, 2] for a cost of 5, and we are left with [5, 4, 1].
We merge [4, 1] for a cost of 5, and we are left with [5, 5].
We merge [5, 5] for a cost of 10, and we are left with [10].
The total cost was 20, and this is the minimum possible.
Example 2:
Input: stones = [3,2,4,1], k = 3
Output: -1
Explanation: After any merge operation, there are 2 piles left, and we can’t merge anymore. So the task is impossible.
Example 3:
Input: stones = [3,5,1,2,6], k = 3
Output: 25
Explanation:
We start with [3, 5, 1, 2, 6].
We merge [5, 1, 2] for a cost of 8, and we are left with [3, 8, 6].
We merge [3, 8, 6] for a cost of 17, and we are left with [17].
The total cost was 25, and this is the minimum possible.
Constraints:
假设 dp[i][j][k]是从 stones[i]到 stones[j]合并为 k 个堆所需要的成本
然后我们把整个合并过程反过来想
最后一步一定是将 k 个堆合并为 1 个堆: dp[i][j][1] = dp[i][j][k] + sum(i,j)
将 stones[i…=j]合并为 k 个堆, 从 i…j 范围中挑选任意一个 m, 左侧为 stones[i…=m], 右侧为 stones[m+1…=j], 左侧合并为 k-1 个堆的成本加上右侧合并为 1 个堆的成本就是整体合并为 k 个堆的成本, dp[i][j][k] = min(dp[i][m][k-1], dp[m+1][j][1])
use std::collections::HashMap;
impl Solution {
fn check(length: i32, k: i32) -> bool {
if length < k {
return false;
}
if length == k {
return true;
}
Solution::check(length - k + 1, k)
}
fn dp(stones: &Vec<i32>, k: usize, i: usize, j: usize, n: usize, cache: &mut HashMap<(usize, usize, usize), i32>) -> i32 {
if let Some(&c) = cache.get(&(i, j, n)) {
return c;
}
if i == j {
if n == 1 {
return 0;
}
return i32::MAX;
}
if n == 1 {
if j - i + 1 == k {
let sum = stones[i..=j].into_iter().sum();
cache.insert((i, j, n), sum);
return sum;
}
let next = Solution::dp(stones, k, i, j, k, cache);
if next == i32::MAX {
return i32::MAX;
}
let ans = next + stones[i..=j].into_iter().sum::<i32>();
cache.insert((i, j, n), ans);
return ans;
}
let mut ans = i32::MAX;
for m in i..j {
let left = Solution::dp(stones, k, i, m, n - 1, cache);
if left == i32::MAX {
continue;
}
let right = Solution::dp(stones, k, m + 1, j, 1, cache);
if right == i32::MAX {
continue;
}
ans = ans.min(left + right);
}
cache.insert((i, j, n), ans);
ans
}
pub fn merge_stones(stones: Vec<i32>, k: i32) -> i32 {
if stones.len() == 1 {
return 0;
}
if !Solution::check(stones.len() as i32, k) {
return -1;
}
Solution::dp(&stones, k as usize, 0, stones.len() - 1, 1, &mut HashMap::new())
}
}