Given an array arr[] of size N and an integer K, the task is to find the minimum cost required to reduce given array to a single element, where cost of replacing K consecutive array elements by their sum is equal to the sum of the K consecutive elements. If it is not possible to reduce given array to a single element, then print -1.
Examples:
Input: arr[] = {3, 5, 1, 2, 6}, K = 3
Output: 25
Explanation:
Replacing {arr[1], arr[2], arr[3]} modifies arr[] = {3, 8, 6}. Cost = 8
Replacing {arr[0], arr[1], arr[2]} modifies arr[] = {17}. Cost = 17.
Therefore, the total cost to merge all the array elements into one = 8 + 17 = 25
Input: arr[] = {3, 2, 4, 1}, K = 3
Output: -1
Merging any K (=3) consecutive array elements left 2 elements in the array.
Therefore, the required output is -1.
Approach: The problem can be solved using Dynamic programming. Following is the recurrence relation:
Since the size of the array reduces by (K – 1) after every replacement operation,
dp[i][j] = min(dp[i][x], dp[x+1][j]), X = i + integer * (K – 1)
where, dp[i][j] stores the minimum cost to merge maximum number of array elements in the interval [i, j] with the left most element arr[i] always involved in merge if possible
Follow the steps below to solve the problem:
- If (N – 1) % (K – 1) != 0 then print -1.
- Initialize an array, say prefixSum[] to store the prefix sum of the given array.
- Initialize a 2D array, say dp[][], where dp[i][j] stores the minimum cost to merge the max number of array elements in the interval [i, j].
- Fill the DP table using the above-mentioned relationship between the DP states.
- Finally, print the value of dp[0][N – 1].
Below is the implementation of the above approach:
C++
#include<bits/stdc++.h>
using namespace std;
int minimumCostToMergeK( int arr[], int K, int N)
{
if ((N - 1) % (K - 1) != 0)
{
return -1;
}
int prefixSum[N + 1] = {0};
for ( int i = 1; i < (N + 1); i++)
{
prefixSum[i] = (prefixSum[i - 1] + arr[i - 1]);
}
int dp[N][N];
memset (dp, 0, sizeof (dp));
for ( int L = K; L < (N + 1); L++)
{
for ( int i = 0; i < (N - L + 1); i++)
{
int j = i + L - 1;
if (L > K)
{
int temp = INT_MAX;
for ( int x = i; x < j; x += K - 1)
{
temp = min(temp, dp[i][x] +
dp[x + 1][j]);
}
dp[i][j] = temp;
}
if ((L - 1) % (K - 1) == 0)
{
dp[i][j] += (prefixSum[j + 1] -
prefixSum[i]);
}
}
}
return dp[0][N - 1];
}
int main()
{
int arr[] = { 3, 5, 1, 2, 6 };
int K = 3;
int N = sizeof (arr) / sizeof (arr[0]);
cout << minimumCostToMergeK(arr, K, N);
}
|
Java
import java.util.*;
class GFG
{
static int minimumCostToMergeK( int arr[], int K, int N)
{
if ((N - 1 ) % (K - 1 ) != 0 )
{
return - 1 ;
}
int []prefixSum = new int [N + 1 ];
for ( int i = 1 ; i < (N + 1 ); i++)
{
prefixSum[i] = (prefixSum[i - 1 ] + arr[i - 1 ]);
}
int [][]dp = new int [N][N];
for ( int L = K; L < (N + 1 ); L++)
{
for ( int i = 0 ; i < (N - L + 1 ); i++)
{
int j = i + L - 1 ;
if (L > K)
{
int temp = Integer.MAX_VALUE;
for ( int x = i; x < j; x += K - 1 )
{
temp = Math.min(temp, dp[i][x] +
dp[x + 1 ][j]);
}
dp[i][j] = temp;
}
if ((L - 1 ) % (K - 1 ) == 0 )
{
dp[i][j] += (prefixSum[j + 1 ] -
prefixSum[i]);
}
}
}
return dp[ 0 ][N - 1 ];
}
public static void main(String[] args)
{
int arr[] = { 3 , 5 , 1 , 2 , 6 };
int K = 3 ;
int N = arr.length;
System.out.print(minimumCostToMergeK(arr, K, N));
}
}
|
Python3
def minimumCostToMergeK(arr, K):
N = len (arr)
if (N - 1 ) % (K - 1 ) ! = 0 :
return - 1
prefixSum = [ 0 ] * (N + 1 )
for i in range ( 1 , N + 1 ):
prefixSum[i] = (prefixSum[i - 1 ]
+ arr[i - 1 ])
dp = [[ 0 ] * N for _ in range (N)]
for L in range (K, N + 1 ):
for i in range (N - L + 1 ):
j = i + L - 1
if L > K:
dp[i][j] = (
min ([dp[i][x] + dp[x + 1 ][j]
for x in range (i, j, K - 1 )]))
if (L - 1 ) % (K - 1 ) = = 0 :
dp[i][j] + = (prefixSum[j + 1 ]
- prefixSum[i])
return dp[ 0 ][N - 1 ]
if __name__ = = "__main__" :
arr = [ 3 , 5 , 1 , 2 , 6 ]
K = 3
print (minimumCostToMergeK(arr, K))
|
C#
using System;
class GFG
{
static int minimumCostToMergeK( int []arr, int K, int N)
{
if ((N - 1) % (K - 1) != 0)
{
return -1;
}
int []prefixSum = new int [N + 1];
for ( int i = 1; i < (N + 1); i++)
{
prefixSum[i] = (prefixSum[i - 1] + arr[i - 1]);
}
int [,]dp = new int [N,N];
for ( int L = K; L < (N + 1); L++)
{
for ( int i = 0; i < (N - L + 1); i++)
{
int j = i + L - 1;
if (L > K)
{
int temp = int .MaxValue;
for ( int x = i; x < j; x += K - 1)
{
temp = Math.Min(temp, dp[i, x] +
dp[x + 1, j]);
}
dp[i, j] = temp;
}
if ((L - 1) % (K - 1) == 0)
{
dp[i, j] += (prefixSum[j + 1] -
prefixSum[i]);
}
}
}
return dp[0, N - 1];
}
public static void Main(String[] args)
{
int []arr = { 3, 5, 1, 2, 6 };
int K = 3;
int N = arr.Length;
Console.Write(minimumCostToMergeK(arr, K, N));
}
}
|
Javascript
<script>
function minimumCostToMergeK(arr , K , N)
{
if ((N - 1) % (K - 1) != 0) {
return -1;
}
var prefixSum = Array(N + 1).fill(0);
for (i = 1; i < (N + 1); i++) {
prefixSum[i] = (prefixSum[i - 1] + arr[i - 1]);
}
var dp = Array(N);
for ( i = 0; i<N;i++)
dp[i] = Array(N).fill(0);
for (L = K; L < (N + 1); L++) {
for (i = 0; i < (N - L + 1); i++) {
var j = i + L - 1;
if (L > K) {
var temp = Number.MAX_VALUE;
for (x = i; x < j; x += K - 1) {
temp = Math.min(temp, dp[i][x] + dp[x + 1][j]);
}
dp[i][j] = temp;
}
if ((L - 1) % (K - 1) == 0) {
dp[i][j] += (prefixSum[j + 1] - prefixSum[i]);
}
}
}
return dp[0][N - 1];
}
var arr = [ 3, 5, 1, 2, 6 ];
var K = 3;
var N = arr.length;
document.write(minimumCostToMergeK(arr, K, N));
</script>
|
Time Complexity: O(N2 * K) // since we are using two nested loops hence the complexity is quadratic
Auxiliary Space: O(N2) // since a dp array of size n*n is used hence the space taken by the algorithm is quadratic