Given two arrays a[] and b[] of size n containing positive integers. Rearrange the elements of both arrays so that the value of: a[0] * b[0] + a[1] * b[1] + ... + a[n-1] * b[n-1] becomes minimum. Each element of a[] and b[] must be used exactly once.
Examples:
Input: a[] = [3, 1, 1], b[] = [6, 5, 4]
Output: 23
Explanation: After rearranging: a[] = [1, 1, 3] and b[] = [6, 5, 4]. Minimum sum = (1 * 6) + (1 * 5) + (3 * 4) = 6 + 5 + 12 = 23.Input: a[] = [6, 1, 9, 5, 4] , b[] = [3, 4, 8, 2, 4]
Output: 80
Explanation: After rearranging: a[] = [1, 4, 5, 6, 9] and b[] = [8, 4, 4, 3, 2]. Minimum sum = (1 * 8) + (4 * 4) + (5 * 4) + (6 * 3) + (9 * 2) = 8 + 16 + 20 + 18 + 18 = 80.
Table of Content
[Naive Approach] Try All Permutations - O(n! × n!) Time O(n) Space
The idea is to generate all possible permutations of both arrays and evaluate every possible pairing. For each pair of permutations, we compute the sum of products and select the minimum among all results.
- Generate all permutations of array a[]
- Generate all permutations of array b[]
- For every pair of permutations:
- Compute sum: a[0]*b[0] + a[1]*b[1] + ... + a[n-1]*b[n-1]
- Keep track of the minimum sum obtained.
#include <bits/stdc++.h>
using namespace std;
// Function to calculate sum of products for a given arrangement
int calc(vector<int> &a, vector<int> &b) {
int sum = 0;
for (int i = 0; i < a.size(); i++) {
sum = (sum + a[i] * b[i]);
}
return sum;
}
// Function to generate all permutations of array a[]
void permuteA(vector<int> &a, int idx, vector<vector<int>> &allA) {
// Base case: if full permutation is formed
if (idx == a.size()) {
allA.push_back(a);
return;
}
// Try swapping current index with all possible positions
for (int i = idx; i < a.size(); i++) {
swap(a[i], a[idx]);
permuteA(a, idx + 1, allA);
// backtrack
swap(a[i], a[idx]);
}
}
// Function to generate all permutations of array b[]
void permuteB(vector<int> &b, int idx, vector<vector<int>> &allB) {
// Base case: if full permutation is formed
if (idx == b.size()) {
allB.push_back(b);
return;
}
// Try swapping current index with all possible positions
for (int i = idx; i < b.size(); i++) {
swap(b[i], b[idx]);
permuteB(b, idx + 1, allB);
// backtrack
swap(b[i], b[idx]);
}
}
int minProductSum(vector<int> a, vector<int> b) {
vector<vector<int>> allA, allB;
// Generate all permutations of both arrays
permuteA(a, 0, allA);
permuteB(b, 0, allB);
int res = INT_MAX;
// Try every possible pairing of permutations
for (auto &x : allA) {
for (auto &y : allB) {
res = min(res, calc(x, y));
}
}
return res;
}
int main() {
vector<int> a = {3, 1, 1};
vector<int> b = {6, 5, 4};
cout << minProductSum(a, b) << endl;
return 0;
}
import java.util.ArrayList;
import java.util.List;
class GFG {
// Function to calculate sum of products for a given arrangement
static int calc(int[] a, int[] b) {
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum = (sum + a[i] * b[i]);
}
return sum;
}
// Function to swap elements in array
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// Function to generate all permutations of array a[]
static void permuteA(int[] a, int idx, List<int[]> allA) {
// Base case: if full permutation is formed
if (idx == a.length) {
allA.add(a.clone());
return;
}
// Try swapping current index with all possible positions
for (int i = idx; i < a.length; i++) {
swap(a, i, idx);
permuteA(a, idx + 1, allA);
// backtrack
swap(a, i, idx);
}
}
// Function to generate all permutations of array b[]
static void permuteB(int[] b, int idx, List<int[]> allB) {
if (idx == b.length) {
allB.add(b.clone());
return;
}
for (int i = idx; i < b.length; i++) {
swap(b, i, idx);
permuteB(b, idx + 1, allB);
swap(b, i, idx);
}
}
static int minProductSum(int[] a, int[] b) {
List<int[]> allA = new ArrayList<>();
List<int[]> allB = new ArrayList<>();
// Generate all permutations
permuteA(a, 0, allA);
permuteB(b, 0, allB);
int res = Integer.MAX_VALUE;
// Try all combinations
for (int[] x : allA) {
for (int[] y : allB) {
res = Math.min(res, calc(x, y));
}
}
return res;
}
public static void main(String[] args) {
int[] a = {3, 1, 1};
int[] b = {6, 5, 4};
System.out.println(minProductSum(a, b));
}
}
# Function to calculate sum of products for a given arrangement
def calc(a, b):
sum = 0
for i in range(len(a)):
sum = (sum + a[i] * b[i])
return sum
# Function to generate all permutations of array a[]
def permuteA(a, idx, allA):
# Base case: if full permutation is formed
if idx == len(a):
allA.append(a[:])
return
# Try swapping current index with all possible positions
for i in range(idx, len(a)):
a[i], a[idx] = a[idx], a[i]
permuteA(a, idx + 1, allA)
# backtrack
a[i], a[idx] = a[idx], a[i]
# Function to generate all permutations of array b[]
def permuteB(b, idx, allB):
# Base case: if full permutation is formed
if idx == len(b):
allB.append(b[:])
return
# Try swapping current index with all possible positions
for i in range(idx, len(b)):
b[i], b[idx] = b[idx], b[i]
permuteB(b, idx + 1, allB)
# backtrack
b[i], b[idx] = b[idx], b[i]
def minProductSum(a, b):
allA = []
allB = []
# Generate all permutations of both arrays
permuteA(a, 0, allA)
permuteB(b, 0, allB)
res = float('inf')
# Try every possible pairing of permutations
for x in allA:
for y in allB:
res = min(res, calc(x, y))
return res
if __name__ == "__main__":
a = [3, 1, 1]
b = [6, 5, 4]
print(minProductSum(a, b))
using System;
using System.Collections.Generic;
class GFG {
// Function to calculate sum of products for a given arrangement
static int calc(List<int> a, List<int> b) {
int sum = 0;
for (int i = 0; i < a.Count; i++) {
sum = (sum + a[i] * b[i]);
}
return sum;
}
// Function to generate all permutations of array a[]
static void permuteA(List<int> a, int idx, List<List<int>> allA) {
// Base case: if full permutation is formed
if (idx == a.Count) {
allA.Add(new List<int>(a));
return;
}
// Try swapping current index with all possible positions
for (int i = idx; i < a.Count; i++) {
int temp = a[i];
a[i] = a[idx];
a[idx] = temp;
permuteA(a, idx + 1, allA);
// backtrack
temp = a[i];
a[i] = a[idx];
a[idx] = temp;
}
}
// Function to generate all permutations of array b[]
static void permuteB(List<int> b, int idx, List<List<int>> allB) {
// Base case: if full permutation is formed
if (idx == b.Count) {
allB.Add(new List<int>(b));
return;
}
// Try swapping current index with all possible positions
for (int i = idx; i < b.Count; i++) {
int temp = b[i];
b[i] = b[idx];
b[idx] = temp;
permuteB(b, idx + 1, allB);
// backtrack
temp = b[i];
b[i] = b[idx];
b[idx] = temp;
}
}
static int minProductSum(List<int> a, List<int> b) {
List<List<int>> allA = new List<List<int>>();
List<List<int>> allB = new List<List<int>>();
// Generate all permutations of both arrays
permuteA(a, 0, allA);
permuteB(b, 0, allB);
int res = int.MaxValue;
// Try every possible pairing of permutations
foreach (List<int> x in allA) {
foreach (List<int> y in allB) {
res = Math.Min(res, calc(x, y));
}
}
return res;
}
static void Main() {
List<int> a = new List<int>() { 3, 1, 1 };
List<int> b = new List<int>() { 6, 5, 4 };
Console.WriteLine(minProductSum(a, b));
}
}
// Function to calculate sum of products for a given arrangement
function calc(a, b) {
let sum = 0;
for (let i = 0; i < a.length; i++) {
sum = (sum + a[i] * b[i]);
}
return sum;
}
// Function to generate all permutations of array a[]
function permuteA(a, idx, allA) {
// Base case: if full permutation is formed
if (idx === a.length) {
allA.push([...a]);
return;
}
// Try swapping current index with all possible positions
for (let i = idx; i < a.length; i++) {
[a[i], a[idx]] = [a[idx], a[i]];
permuteA(a, idx + 1, allA);
// backtrack
[a[i], a[idx]] = [a[idx], a[i]];
}
}
// Function to generate all permutations of array b[]
function permuteB(b, idx, allB) {
// Base case: if full permutation is formed
if (idx === b.length) {
allB.push([...b]);
return;
}
// Try swapping current index with all possible positions
for (let i = idx; i < b.length; i++) {
[b[i], b[idx]] = [b[idx], b[i]];
permuteB(b, idx + 1, allB);
// backtrack
[b[i], b[idx]] = [b[idx], b[i]];
}
}
function minProductSum(a, b) {
let allA = [];
let allB = [];
// Generate all permutations of both arrays
permuteA(a, 0, allA);
permuteB(b, 0, allB);
let res = Number.MAX_SAFE_INTEGER;
// Try every possible pairing of permutations
for (let x of allA) {
for (let y of allB) {
res = Math.min(res, calc(x, y));
}
}
return res;
}
// Drive code
let a = [3, 1, 1];
let b = [6, 5, 4];
console.log(minProductSum(a, b));
Output
23
[Expected Approach] Sorting + Greedy - O(n log n) Time and O(1) Space
To minimize the sum of products, we minimize the contribution of larger elements. Since larger elements have a higher impact on the final result, they should be paired with smaller elements instead of other large elements.
To achieve this, we sort one array in increasing order and the other in decreasing order. This ensures that each large element is multiplied with a small element, which reduces its contribution and leads to the minimum possible sum of products.
- Sort array a[] in increasing order.
- Sort array b[] in decreasing order.
- Initialize sum = 0.
- Traverse both arrays: sum += a[i] * b[i]
- Return sum.
Consider: a[] = {3, 1, 1} and b[] = {6, 5, 4}
Step 1: To minimize the sum, we first sort array a[] in increasing order and array b[] in decreasing order.
- a[] = {1, 1, 3}
- b[] = {6, 5, 4}
Step 2: Now, multiply elements at the same index of both arrays and compute the sum.
- i = 0 -> 1 × 6 = 6
- i = 1 -> 1 × 5 = 5
- i = 2 -> 3 × 4 = 12
Total sum = 6 + 5 + 12 = 23
#include <bits/stdc++.h>
using namespace std;
int minProductSum(vector<int> &a, vector<int> &b) {
// Sort a[] in increasing order
sort(a.begin(), a.end());
// Sort b[] in decreasing order
sort(b.begin(), b.end(), greater<int>());
int sum = 0;
// Multiply smallest element of a[]
// with largest element of b[]
for (int i = 0; i < a.size(); i++) {
sum = sum + a[i] * b[i];
}
return sum;
}
int main() {
vector<int> a = {3, 1, 1};
vector<int> b = {6, 5, 4};
cout << minProductSum(a, b) << endl;
return 0;
}
import java.util.Arrays;
class GFG {
public static int minProductSum(int[] a, int[] b) {
// Sort a[] in increasing order
Arrays.sort(a);
// Sort b[] in decreasing order
Arrays.sort(b);
// Reverse b[] to make it decreasing order
for (int i = 0; i < b.length / 2; i++) {
int temp = b[i];
b[i] = b[b.length - 1 - i];
b[b.length - 1 - i] = temp;
}
int sum = 0;
// Multiply smallest element of a[]
// with largest element of b[]
for (int i = 0; i < a.length; i++) {
sum = sum + a[i] * b[i];
}
return sum;
}
public static void main(String[] args) {
int[] a = {3, 1, 1};
int[] b = {6, 5, 4};
System.out.println(minProductSum(a, b));
}
}
def minProductSum(a, b):
# Sort a[] in increasing order
a.sort()
# Sort b[] in decreasing order
b.sort(reverse=True)
sum = 0
# Multiply smallest element of a[]
# with largest element of b[]
for i in range(len(a)):
sum = sum + a[i] * b[i]
return sum
if __name__ == "__main__":
a = [3, 1, 1]
b = [6, 5, 4]
print(minProductSum(a, b))
using System;
using System.Collections.Generic;
using System.Linq;
class GFG {
static int minProductSum(List<int> a, List<int> b) {
// Sort a[] in increasing order
a.Sort();
// Sort b[] in decreasing order
b = b.OrderByDescending(x => x).ToList();
int sum = 0;
// Multiply smallest element of a[]
// with largest element of b[]
for (int i = 0; i < a.Count; i++) {
sum = sum + a[i] * b[i];
}
return sum;
}
static void Main() {
List<int> a = new List<int>{3, 1, 1};
List<int> b = new List<int>{6, 5, 4};
Console.WriteLine(minProductSum(a, b));
}
}
function minProductSum(a, b) {
// Sort a[] in increasing order
a.sort((x, y) => x - y);
// Sort b[] in decreasing order
b.sort((x, y) => y - x);
let sum = 0;
// Multiply smallest element of a[]
// with largest element of b[]
for (let i = 0; i < a.length; i++) {
sum = sum + a[i] * b[i];
}
return sum;
}
// Driver code
let a = [3, 1, 1];
let b = [6, 5, 4];
console.log(minProductSum(a, b));
Output
23