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 = 25Input: 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++ program to implement // the above approach #include<bits/stdc++.h> using namespace std;
// Function to find the minimum cost // to reduce given array to a single // element by replacing consecutive // K array elements int minimumCostToMergeK( int arr[], int K, int N)
{ // If (N - 1) is not
// multiple of (K - 1)
if ((N - 1) % (K - 1) != 0)
{
return -1;
}
// Store prefix sum of the array
int prefixSum[N + 1] = {0};
// Iterate over the range [1, N]
for ( int i = 1; i < (N + 1); i++)
{
// Update prefixSum[i]
prefixSum[i] = (prefixSum[i - 1] + arr[i - 1]);
}
// dp[i][j]: Store minimum cost to
// merge array elements interval [i, j]
int dp[N][N];
memset (dp, 0, sizeof (dp));
// L: Stores length of interval [i, j]
for ( int L = K; L < (N + 1); L++)
{
// Iterate over each interval
// [i, j] of length L in in [0, N]
for ( int i = 0; i < (N - L + 1); i++)
{
// Stores index of last element
// of the interval [i, j]
int j = i + L - 1;
// If L is greater than K
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]);
}
// Update dp[i][j]
dp[i][j] = temp;
}
// If (L - 1) is multiple of (K - 1)
if ((L - 1) % (K - 1) == 0)
{
// Update dp[i][j]
dp[i][j] += (prefixSum[j + 1] -
prefixSum[i]);
}
}
}
// Return dp[0][N - 1]
return dp[0][N - 1];
} // Driver Code int main()
{ int arr[] = { 3, 5, 1, 2, 6 };
int K = 3;
// Stores length of arr
int N = sizeof (arr) / sizeof (arr[0]);
cout << minimumCostToMergeK(arr, K, N);
} // This code is contributed by rag2127 |
// Java program to implement // the above approach import java.util.*;
class GFG
{ // Function to find the minimum cost
// to reduce given array to a single
// element by replacing consecutive
// K array elements
static int minimumCostToMergeK( int arr[], int K, int N)
{
// If (N - 1) is not
// multiple of (K - 1)
if ((N - 1 ) % (K - 1 ) != 0 )
{
return - 1 ;
}
// Store prefix sum of the array
int []prefixSum = new int [N + 1 ];
// Iterate over the range [1, N]
for ( int i = 1 ; i < (N + 1 ); i++)
{
// Update prefixSum[i]
prefixSum[i] = (prefixSum[i - 1 ] + arr[i - 1 ]);
}
// dp[i][j]: Store minimum cost to
// merge array elements interval [i, j]
int [][]dp = new int [N][N];
// L: Stores length of interval [i, j]
for ( int L = K; L < (N + 1 ); L++)
{
// Iterate over each interval
// [i, j] of length L in in [0, N]
for ( int i = 0 ; i < (N - L + 1 ); i++)
{
// Stores index of last element
// of the interval [i, j]
int j = i + L - 1 ;
// If L is greater than K
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]);
}
// Update dp[i][j]
dp[i][j] = temp;
}
// If (L - 1) is multiple of (K - 1)
if ((L - 1 ) % (K - 1 ) == 0 )
{
// Update dp[i][j]
dp[i][j] += (prefixSum[j + 1 ] -
prefixSum[i]);
}
}
}
// Return dp[0][N - 1]
return dp[ 0 ][N - 1 ];
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 3 , 5 , 1 , 2 , 6 };
int K = 3 ;
// Stores length of arr
int N = arr.length;
System.out.print(minimumCostToMergeK(arr, K, N));
}
} // This code is contributed by shikhasingrajput |
# Python3 program to implement # the above approach # Function to find the minimum cost # to reduce given array to a single # element by replacing consecutive # K array elements def minimumCostToMergeK(arr, K):
# Stores length of arr
N = len (arr)
# If (N - 1) is not
# multiple of (K - 1)
if (N - 1 ) % (K - 1 ) ! = 0 :
return - 1
# Store prefix sum of the array
prefixSum = [ 0 ] * (N + 1 )
# Iterate over the range [1, N]
for i in range ( 1 , N + 1 ):
# Update prefixSum[i]
prefixSum[i] = (prefixSum[i - 1 ]
+ arr[i - 1 ])
# dp[i][j]: Store minimum cost to
# merge array elements interval [i, j]
dp = [[ 0 ] * N for _ in range (N)]
# L: Stores length of interval [i, j]
for L in range (K, N + 1 ):
# Iterate over each interval
# [i, j] of length L in in [0, N]
for i in range (N - L + 1 ):
# Stores index of last element
# of the interval [i, j]
j = i + L - 1
# If L is greater than K
if L > K:
# Update dp[i][j]
dp[i][j] = (
min ([dp[i][x] + dp[x + 1 ][j]
for x in range (i, j, K - 1 )]))
# If (L - 1) is multiple of (K - 1)
if (L - 1 ) % (K - 1 ) = = 0 :
# Update dp[i][j]
dp[i][j] + = (prefixSum[j + 1 ]
- prefixSum[i])
# Return dp[0][N - 1]
return dp[ 0 ][N - 1 ]
if __name__ = = "__main__" :
arr = [ 3 , 5 , 1 , 2 , 6 ]
K = 3
print (minimumCostToMergeK(arr, K))
|
// C# program to implement // the above approach using System;
class GFG
{ // Function to find the minimum cost
// to reduce given array to a single
// element by replacing consecutive
// K array elements
static int minimumCostToMergeK( int []arr, int K, int N)
{
// If (N - 1) is not
// multiple of (K - 1)
if ((N - 1) % (K - 1) != 0)
{
return -1;
}
// Store prefix sum of the array
int []prefixSum = new int [N + 1];
// Iterate over the range [1, N]
for ( int i = 1; i < (N + 1); i++)
{
// Update prefixSum[i]
prefixSum[i] = (prefixSum[i - 1] + arr[i - 1]);
}
// dp[i,j]: Store minimum cost to
// merge array elements interval [i, j]
int [,]dp = new int [N,N];
// L: Stores length of interval [i, j]
for ( int L = K; L < (N + 1); L++)
{
// Iterate over each interval
// [i, j] of length L in in [0, N]
for ( int i = 0; i < (N - L + 1); i++)
{
// Stores index of last element
// of the interval [i, j]
int j = i + L - 1;
// If L is greater than K
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]);
}
// Update dp[i,j]
dp[i, j] = temp;
}
// If (L - 1) is multiple of (K - 1)
if ((L - 1) % (K - 1) == 0)
{
// Update dp[i,j]
dp[i, j] += (prefixSum[j + 1] -
prefixSum[i]);
}
}
}
// Return dp[0,N - 1]
return dp[0, N - 1];
}
// Driver Code
public static void Main(String[] args)
{
int []arr = { 3, 5, 1, 2, 6 };
int K = 3;
// Stores length of arr
int N = arr.Length;
Console.Write(minimumCostToMergeK(arr, K, N));
}
} // This code is contributed by 29AjayKumar |
<script> // javascript program to implement // the above approach // Function to find the minimum cost
// to reduce given array to a single
// element by replacing consecutive
// K array elements
function minimumCostToMergeK(arr , K , N)
{
// If (N - 1) is not
// multiple of (K - 1)
if ((N - 1) % (K - 1) != 0) {
return -1;
}
// Store prefix sum of the array
var prefixSum = Array(N + 1).fill(0);
// Iterate over the range [1, N]
for (i = 1; i < (N + 1); i++) {
// Update prefixSum[i]
prefixSum[i] = (prefixSum[i - 1] + arr[i - 1]);
}
// dp[i][j]: Store minimum cost to
// merge array elements interval [i, j]
var dp = Array(N);
for ( i = 0; i<N;i++)
dp[i] = Array(N).fill(0);
// L: Stores length of interval [i, j]
for (L = K; L < (N + 1); L++) {
// Iterate over each interval
// [i, j] of length L in in [0, N]
for (i = 0; i < (N - L + 1); i++) {
// Stores index of last element
// of the interval [i, j]
var j = i + L - 1;
// If L is greater than K
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]);
}
// Update dp[i][j]
dp[i][j] = temp;
}
// If (L - 1) is multiple of (K - 1)
if ((L - 1) % (K - 1) == 0) {
// Update dp[i][j]
dp[i][j] += (prefixSum[j + 1] - prefixSum[i]);
}
}
}
// Return dp[0][N - 1]
return dp[0][N - 1];
}
// Driver Code
var arr = [ 3, 5, 1, 2, 6 ];
var K = 3;
// Stores length of arr
var N = arr.length;
document.write(minimumCostToMergeK(arr, K, N));
// This code is contributed by todaysgaurav </script> |
25
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