Minimum sum of multiplications of n numbers
Last Updated :
30 Sep, 2023
Given n integers. The task is to minimize the sum of multiplication of all the numbers by taking two adjacent numbers at a time and putting back their sum % 100 till a number is left.
Examples :
Input : 40 60 20
Output : 2400
Explanation: There are two possible cases:
1st possibility: Take 40 and 60, so multiplication=2400
and put back (60+40) % 100 = 0, making it 0, 20.
Multiplying 0 and 20 we get 0 so
multiplication = 2400+0 = 2400. Put back (0+20)%100 = 20.
2nd possibility: take 60 and 20, so 60*20 = 1200,
put back (60+20)%100 = 80, making it [40, 80]
multiply 40*80 to get 3200, so multiplication
sum = 1200+3200 = 4400. Put back (40+80)%100 = 20
Input : 5 6
Output : 30
Explanation: Only possibility is 5*6=30
Approach: The problem is a variation of Matrix chain Multiplication Dynamic Programming
The idea is to partition N numbers into every possible value of k. Solve recursively for smaller parts and add the multiplication and store the minimum of them. Since we are dividing it into k parts, for every DPi,j we will have k partitions i<=k<j , store the minimum of them. So we get the formula similar to Matrix chain Multiplication Dynamic Programming.
DPi,j = min(DPi,j , (DPi,k+DPk+1,j+(cumulative_sumi,k*cumulative_sumk+1,j) ) )
for every i<=k<j.
Since many subproblems will be repeating, hence we use memoization to store the values in a nXn matrix.
Given below is the illustration of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
long long dp[1000][1000];
long long sum( int a[], int i, int j)
{
long long ans = 0;
for ( int m = i; m <= j; m++)
ans = (ans + a[m]) % 100;
return ans;
}
long long solve( int a[], int i, int j)
{
if (i == j)
return 0;
if (dp[i][j] != -1)
return dp[i][j];
dp[i][j] = INT_MAX;
for ( int k = i; k < j; k++)
{
dp[i][j] = min(dp[i][j], (solve(a, i, k) +
solve(a, k + 1, j) +
(sum(a, i, k) * sum(a, k + 1, j))));
}
return dp[i][j];
}
void initialize( int n)
{
for ( int i = 0; i <= n; i++)
for ( int j = 0; j <= n; j++)
dp[i][j] = -1;
}
int main() {
int a[] = {40, 60, 20};
int n = sizeof (a) / sizeof (a[0]);
initialize(n);
cout << solve(a, 0, n - 1) << endl;
return 0;
}
|
Java
import java.io.*;
import java.math.*;
class GFG
{
static long dp[][] = new long [ 1000 ][ 1000 ];
static long sum( int a[], int i, int j)
{
long ans = 0 ;
for ( int m = i; m <= j; m++)
ans = (ans + a[m]) % 100 ;
return ans;
}
static long solve( int a[], int i, int j)
{
if (i == j)
return 0 ;
if (dp[i][j] != - 1 )
return dp[i][j];
dp[i][j] = 100000000 ;
for ( int k = i; k < j; k++)
{
dp[i][j] = Math.min(dp[i][j], (solve(a, i, k) +
solve(a, k + 1 , j) +
(sum(a, i, k) * sum(a, k + 1 ,j))));
}
return dp[i][j];
}
static void initialize( int n)
{
for ( int i = 0 ; i <= n; i++)
for ( int j = 0 ; j <= n; j++)
dp[i][j] = - 1 ;
}
public static void main(String args[])
{
int a[] = { 40 , 60 , 20 };
int n = a.length;
initialize(n);
System.out.println(solve(a, 0 , n - 1 ));
}
}
|
Python3
import numpy as np
import sys
dp = np.zeros(( 1000 , 1000 ))
def sum (a, i, j) :
ans = 0
for m in range (i, j + 1 ) :
ans = (ans + a[m]) % 100
return ans
def solve(a, i, j) :
if (i = = j) :
return 0
if (dp[i][j] ! = - 1 ) :
return dp[i][j]
dp[i][j] = sys.maxsize
for k in range (i, j) :
dp[i][j] = min (dp[i][j], (solve(a, i, k) + solve(a, k + 1 , j)
+ ( sum (a, i, k) * sum (a, k + 1 , j))))
return dp[i][j]
def initialize(n) :
for i in range (n + 1 ) :
for j in range (n + 1 ) :
dp[i][j] = - 1
if __name__ = = "__main__" :
a = [ 40 , 60 , 20 ]
n = len (a)
initialize(n)
print ( int (solve(a, 0 , n - 1 )))
|
C#
using System;
class GFG
{
static long [,]dp = new long [1000, 1000];
static long sum( int []a, int i, int j)
{
long ans = 0;
for ( int m = i; m <= j; m++)
ans = (ans + a[m]) % 100;
return ans;
}
static long solve( int []a, int i, int j)
{
if (i == j)
return 0;
if (dp[i, j] != -1)
return dp[i, j];
dp[i, j] = 100000000;
for ( int k = i; k < j; k++)
{
dp[i, j] = Math.Min(dp[i, j], (solve(a, i, k) +
solve(a, k + 1, j) +
(sum(a, i, k) * sum(a, k + 1, j))));
}
return dp[i, j];
}
static void initialize( int n)
{
for ( int i = 0; i <= n; i++)
for ( int j = 0; j <= n; j++)
dp[i, j] = -1;
}
public static void Main()
{
int []a = {40, 60, 20};
int n = a.Length;
initialize(n);
Console.WriteLine(solve(a, 0, n - 1));
}
}
|
Javascript
<script>
var dp = Array.from(Array(1000), ()=>Array(1000));
function sum( a, i, j)
{
var ans = 0;
for ( var m = i; m <= j; m++)
ans = (ans + a[m]) % 100;
return ans;
}
function solve( a, i, j)
{
if (i == j)
return 0;
if (dp[i][j] != -1)
return dp[i][j];
dp[i][j] = 1000000000;
for ( var k = i; k < j; k++)
{
dp[i][j] = Math.min(dp[i][j], (solve(a, i, k) +
solve(a, k + 1, j) +
(sum(a, i, k) * sum(a, k + 1, j))));
}
return dp[i][j];
}
function initialize(n)
{
for ( var i = 0; i <= n; i++)
for ( var j = 0; j <= n; j++)
dp[i][j] = -1;
}
var a = [40, 60, 20];
var n = a.length;
initialize(n);
document.write( solve(a, 0, n - 1));
</script>
|
PHP
<?php
$dp = array ( array ());
function sum( $a , $i , $j )
{
$ans = 0;
for ( $m = $i ; $m <= $j ; $m ++)
$ans = ( $ans + $a [ $m ]) % 100;
return $ans ;
}
function solve( $a , $i , $j )
{
global $dp ;
if ( $i == $j )
return 0;
if ( $dp [ $i ][ $j ] != -1)
return $dp [ $i ][ $j ];
$dp [ $i ][ $j ] = PHP_INT_MAX;
for ( $k = $i ; $k < $j ; $k ++)
{
$dp [ $i ][ $j ] = min( $dp [ $i ][ $j ],
(solve( $a , $i , $k ) +
solve( $a , $k + 1, $j ) +
(sum( $a , $i , $k ) *
sum( $a , $k + 1, $j ))));
}
return $dp [ $i ][ $j ];
}
function initialize( $n )
{
global $dp ;
for ( $i = 0; $i <= $n ; $i ++)
for ( $j = 0; $j <= $n ; $j ++)
$dp [ $i ][ $j ] = -1;
}
$a = array (40, 60, 20);
$n = count ( $a );
initialize( $n );
echo solve( $a , 0, $n - 1) ;
?>
|
Time Complexity: O(n^3)
Auxiliary Space: O(n^2)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a DP of size N*N to store the computations of subproblems.
- Initialize Dp with 0.
- Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
- Return the final solution stored in dp[0][n-1].
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
long long sum( int a[], int i, int j)
{
long long ans = 0;
for ( int m = i; m <= j; m++)
ans = (ans + a[m]) % 100;
return ans;
}
long long solve( int a[], int n)
{
long long dp[n][n];
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < n; j++) {
dp[i][j] = 0;
}
}
for ( int len = 2; len <= n; len++) {
for ( int i = 0; i < n - len + 1; i++) {
int j = i + len - 1;
dp[i][j] = INT_MAX;
for ( int k = i; k < j; k++) {
dp[i][j] = min(dp[i][j], (dp[i][k] +
dp[k + 1][j] +
(sum(a, i, k) * sum(a, k + 1, j))));
}
}
}
return dp[0][n - 1];
}
int main()
{
int a[] = { 40, 60, 20 };
int n = sizeof (a) / sizeof (a[0]);
cout << solve(a, n) << endl;
return 0;
}
|
Java
import java.util.Arrays;
public class GFG {
public static long sum( int [] a, int i, int j) {
long ans = 0 ;
for ( int m = i; m <= j; m++)
ans = (ans + a[m]) % 100 ;
return ans;
}
public static long solve( int [] a, int n) {
long [][] dp = new long [n][n];
for ( int i = 0 ; i < n; i++) {
Arrays.fill(dp[i], 0 );
}
for ( int len = 2 ; len <= n; len++) {
for ( int i = 0 ; i < n - len + 1 ; i++) {
int j = i + len - 1 ;
dp[i][j] = Integer.MAX_VALUE;
for ( int k = i; k < j; k++) {
dp[i][j] = Math.min(dp[i][j], (dp[i][k] +
dp[k + 1 ][j] +
(sum(a, i, k) * sum(a, k + 1 , j))));
}
}
}
return dp[ 0 ][n - 1 ];
}
public static void main(String[] args) {
int [] a = { 40 , 60 , 20 };
int n = a.length;
System.out.println(solve(a, n));
}
}
|
Python3
def sum_arr(a, i, j):
ans = 0
for m in range (i, j + 1 ):
ans = (ans + a[m]) % 100
return ans
def solve(a, n):
dp = [[ 0 ] * n for _ in range (n)]
for length in range ( 2 , n + 1 ):
for i in range (n - length + 1 ):
j = i + length - 1
dp[i][j] = float ( 'inf' )
for k in range (i, j):
dp[i][j] = min (dp[i][j], (dp[i][k] +
dp[k + 1 ][j] +
(sum_arr(a, i, k) * sum_arr(a, k + 1 , j))))
return dp[ 0 ][n - 1 ]
a = [ 40 , 60 , 20 ]
n = len (a)
print (solve(a, n))
|
C#
using System;
namespace CumulativeSumExample {
class Program {
static long Sum( int [] a, int i, int j)
{
long ans = 0;
for ( int m = i; m <= j; m++)
ans = (ans + a[m]) % 100;
return ans;
}
static long Solve( int [] a, int n)
{
long [, ] dp = new long [n, n];
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < n; j++) {
dp[i, j] = 0;
}
}
for ( int len = 2; len <= n; len++) {
for ( int i = 0; i < n - len + 1; i++) {
int j = i + len - 1;
dp[i, j] = int .MaxValue;
for ( int k = i; k < j; k++) {
dp[i, j] = Math.Min(
dp[i, j], (dp[i, k] + dp[k + 1, j]
+ (Sum(a, i, k)
* Sum(a, k + 1, j))));
}
}
}
return dp[0, n - 1];
}
static void Main( string [] args)
{
int [] a = { 40, 60, 20 };
int n = a.Length;
Console.WriteLine(Solve(a, n));
}
}
}
|
Javascript
function sum(a, i, j) {
let ans = 0;
for (let m = i; m <= j; m++) {
ans = (ans + a[m]) % 100;
}
return ans;
}
function solve(a, n) {
const dp = new Array(n).fill(0).map(() => new Array(n).fill(0));
for (let len = 2; len <= n; len++) {
for (let i = 0; i < n - len + 1; i++) {
const j = i + len - 1;
dp[i][j] = Number.MAX_VALUE;
for (let k = i; k < j; k++) {
dp[i][j] = Math.min(
dp[i][j],
dp[i][k] + dp[k + 1][j] + sum(a, i, k) * sum(a, k + 1, j)
);
}
}
}
return dp[0][n - 1];
}
const a = [40, 60, 20];
const n = a.length;
console.log(solve(a, n));
|
Time Complexity: O(n^3)
Auxiliary Space: O(n^2)
Share your thoughts in the comments
Please Login to comment...