Minimum cost of reducing Array by merging any adjacent elements repetitively
Last Updated :
14 Jun, 2021
Given an array arr[] of N numbers. We can merge two adjacent numbers into one and the cost of merging the two numbers is equal to the sum of the two values. The task is to find the total minimum cost of merging all the numbers.
Examples:
Input: arr[] = { 6, 4, 4, 6 }
Output: 40
Explanation:
Following is the optimal way of merging numbers to get the total minimum cost of merging of numbers:
1. Merge (6, 4), then array becomes, arr[] = {10, 4, 6} and cost = 10
2. Merge (4, 6), then array becomes, arr[] = {10, 10} and cost = 10
3. Merge (10, 10), then array becomes, arr[] = {20} and cost = 20
Hence the total cost is 10 + 10 + 20 = 40.
Input: arr[] = { 3, 2, 4, 1 }
Output: 20
Explanation:
Following is the optimal way of merging numbers to get the total minimum cost of merging of numbers:
1. Merge (3, 2), then array becomes, arr[] = {5, 4, 1} and cost = 5
2. Merge (4, 1), then array becomes, arr[] = {5, 5} and cost = 5
3. Merge (5, 5), then array becomes, arr[] = {10} and cost = 10
Hence the total cost is 5 + 5 + 10 = 20.
Approach: The problem can be solved using Dynamic Programming. Below are the steps:
- The idea is to merge 2 consecutive numbers into every possible index i and then solve recursively for left and right parts of index i.
- Add the result of merging two numbers in above steps and store the minimum of them.
- Since there are many subproblems that are repeating, hence we use memoization to store the values in a NxN matrix.
- The recurrence relation for the above problem statement is given as:
dp[i][j] = min(dp[i][j], (sum[i][j] + dp[i][k] + dp[k + 1][j])), for every (i ? k lt; j)
5. Now dp[1][N] will give the minimum total cost of merging all the numbers.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int mergeTwoNumbers(vector< int >& numbers)
{
int len, i, j, k;
int n = numbers.size();
if (numbers.size() == 0) {
return 0;
}
vector< int > prefixSum(n + 1, 0);
for ( int i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1]
+ numbers[i - 1];
}
vector<vector< int > > dp(
n + 1,
vector< int >(n + 1));
for ( int i = 1; i <= n; i++) {
dp[i][i] = 0;
}
for (len = 2; len <= n; len++) {
for (i = 1; i <= n - len + 1; i++) {
j = i + len - 1;
int sum = prefixSum[j]
- prefixSum[i - 1];
dp[i][j] = INT_MAX;
for (k = i; k < j; k++) {
dp[i][j]
= min(dp[i][j],
dp[i][k]
+ dp[k + 1][j]
+ sum);
}
}
}
return dp[1][n];
}
int main()
{
vector< int > arr1 = { 6, 4, 4, 6 };
cout << mergeTwoNumbers(arr1)
<< endl;
return 0;
}
|
Java
import java.util.*;
class GFG{
static int mergeTwoNumbers( int []numbers)
{
int len, i, j, k;
int n = numbers.length;
if (numbers.length == 0 )
{
return 0 ;
}
int []prefixSum = new int [n + 1 ];
for (i = 1 ; i <= n; i++)
{
prefixSum[i] = prefixSum[i - 1 ] +
numbers[i - 1 ];
}
int [][]dp = new int [n + 1 ][n + 1 ];
for (len = 2 ; len <= n; len++)
{
for (i = 1 ; i <= n - len + 1 ; i++)
{
j = i + len - 1 ;
int sum = prefixSum[j] -
prefixSum[i - 1 ];
dp[i][j] = Integer.MAX_VALUE;
for (k = i; k < j; k++)
{
dp[i][j] = Math.min(dp[i][j],
dp[i][k] +
dp[k + 1 ][j] +
sum);
}
}
}
return dp[ 1 ][n];
}
public static void main(String[] args)
{
int []arr1 = { 6 , 4 , 4 , 6 };
System.out.print(mergeTwoNumbers(arr1) + "\n" );
}
}
|
Python3
import sys
def mergeTwoNumbers(numbers):
n = len (numbers)
if ( len (numbers) = = 0 ):
return 0
prefixSum = [ 0 ] * (n + 1 )
for i in range ( 1 , n + 1 ):
prefixSum[i] = (prefixSum[i - 1 ] +
numbers[i - 1 ])
dp = [[ 0 for i in range (n + 1 )]
for j in range (n + 1 )]
for i in range ( 1 , n + 1 ):
dp[i][i] = 0
for p in range ( 2 , n + 1 ):
for i in range ( 1 , n - p + 2 ):
j = i + p - 1
sum = prefixSum[j] - prefixSum[i - 1 ]
dp[i][j] = sys.maxsize
for k in range (i, j):
dp[i][j] = min (dp[i][j],
(dp[i][k] +
dp[k + 1 ][j] + sum ))
return dp[ 1 ][n]
arr1 = [ 6 , 4 , 4 , 6 ]
print (mergeTwoNumbers(arr1))
|
C#
using System;
class GFG{
static int mergeTwoNumbers( int []numbers)
{
int len, i, j, k;
int n = numbers.Length;
if (numbers.Length == 0)
{
return 0;
}
int []prefixSum = new int [n + 1];
for (i = 1; i <= n; i++)
{
prefixSum[i] = prefixSum[i - 1] +
numbers[i - 1];
}
int [,]dp = new int [n + 1, n + 1];
for (len = 2; len <= n; len++)
{
for (i = 1; i <= n - len + 1; i++)
{
j = i + len - 1;
int sum = prefixSum[j] -
prefixSum[i - 1];
dp[i,j] = int .MaxValue;
for (k = i; k < j; k++)
{
dp[i, j] = Math.Min(dp[i, j],
dp[i, k] +
dp[k + 1, j] +
sum);
}
}
}
return dp[1, n];
}
public static void Main(String[] args)
{
int []arr1 = { 6, 4, 4, 6 };
Console.Write(mergeTwoNumbers(arr1) + "\n" );
}
}
|
Javascript
<script>
function mergeTwoNumbers(numbers)
{
var len, i, j, k;
var n = numbers.length;
if (numbers.length == 0) {
return 0;
}
var prefixSum = Array(n+1).fill(0);
for ( var i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1]
+ numbers[i - 1];
}
var dp = Array.from(Array(n+1), ()=>Array(n+1));
for ( var i = 1; i <= n; i++) {
dp[i][i] = 0;
}
for (len = 2; len <= n; len++) {
for (i = 1; i <= n - len + 1; i++) {
j = i + len - 1;
var sum = prefixSum[j]
- prefixSum[i - 1];
dp[i][j] = 1000000000;
for (k = i; k < j; k++) {
dp[i][j]
= Math.min(dp[i][j],
dp[i][k]
+ dp[k + 1][j]
+ sum);
}
}
}
return dp[1][n];
}
var arr1 = [6, 4, 4, 6];
document.write( mergeTwoNumbers(arr1))
</script>
|
Time Complexity: O(N3)
Auxiliary Space Complexity: O(N2)
Share your thoughts in the comments
Please Login to comment...