The Minimum Cost to Merge Stones problem is a classical dynamic programming problem. The problem statement is described as follows:
Suppose we have ‘n‘ stones arranged in a line, where each stone has some value. We merge adjacent stones into a single pile repeatedly until there is only one pile remaining. The cost of merging two adjacent piles is equal to the sum of their values. Find the minimum cost of merging all stones into a single pile.
To solve this problem with dynamic programming, we have to divide the problem into smaller subproblems and solve them recursively. Let ‘dp[i][j][k]‘ be the minimum cost of merging the stones from index ‘i‘ to index ‘j‘ into ‘k‘ piles. We need to calculate ‘dp[1][n][1]‘, which is the minimum cost of merging all stones into a single pile.
To calculate ‘dp[i][j][k]‘, we can divide the stones into two parts: stones ‘i‘ to ‘m‘ and stones ‘m+1‘ to ‘j‘. The two parts can be merged into ‘1‘ pile and this reduces the number of piles by ‘1‘. The cost of this merge is ‘dp[i][m][1] + dp[m+1][j][k-1]‘.
We also need to consider the situation where the two parts cannot be merged into ‘1‘ pile. In this case, we merge the two parts into ‘k‘ piles separately, and the cost of this merge is ‘dp[i][m][p] + dp[m+1][j][k-p]‘, where ‘1<=p<k‘.
Therefore, to calculate ‘dp[i][j][k]‘, we have to enumerate all ‘m‘ and ‘p‘ and choose the minimum cost as follows:
for i=1 to n
for j=i to n
for k=2 to K
for m=i to j-1
dp[i][j][k] = min(dp[i][j][k], dp[i][m][1] + dp[m+1][j][k-1])
for p=1 to k-1
dp[i][j][k] = min(dp[i][j][k], dp[i][m][p] + dp[m+1][j][k-p])
Finally, the minimum cost of merging all stones into a single pile can be obtained as ‘dp[1][n][1]‘.
Here’s the Java implementation of the above solution:
public int mergeStones(int[] stones, int K) {
int n = stones.length;
if ((n - 1) % (K - 1) != 0) {
return -1;
}
int[] prefixSum = new int[n + 1];
for (int i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i] + stones[i];
}
int[][][] dp = new int[n + 1][n + 1][K + 1];
for (int len = K; len <= n; len++) {
for (int i = 1, j = i + len - 1; j <= n; i++, j++) {
for (int k = 2; k <= K; k++) {
dp[i][j][k] = Integer.MAX_VALUE;
for (int m = i; m < j; m += K - 1) {
dp[i][j][k] = Math.min(dp[i][j][k], dp[i][m][1] + dp[m + 1][j][k - 1]);
}
if ((j - i) % (K - 1) == 0) {
dp[i][j][1] = dp[i][j][k] + prefixSum[j] - prefixSum[i - 1];
}
}
}
}
return dp[1][n][1];
}
In this implementation, ‘stones‘ is the array of values of the stones, and ‘K‘ is the number of stones that can be merged into a single pile. ‘prefixSum‘ is an array of prefix sums of ‘stones‘ for efficient calculation of the cost of merging. The function returns ‘-1‘ if the stones cannot be merged into a single pile. Otherwise, it returns the minimum cost of merging all stones into a single pile.