Divide an array into K subarray with the given condition

Given an array arr[] and an integer K. The task is to divide the array into K parts ( subarray ) such that the sum of the values of all subarray is minimum.

The value of every subarray is defined as:

  • Take the maximum from that subarray.
  • Subtract each element of the subarray with the maximum.
  • Take the sum of all the values after subtraction.

The task is to minimize the sum of the values after dividing the array into K parts.



Examples:

Input: arr[] = { 2, 9, 5, 4, 8, 3, 6 }, K = 2
Output: 19
Explanation:
The two groups are : {2} with max = 2 and {9, 5, 4, 8, 3, 6} with max=9,
sum of difference of first group = 2 – 2 = 0,
sum of difference of second group = (9-9) + (9-5) + (9-4) + (9-8) + (9-3) + (9-6) = 19

Input: arr[] = { 12, 20, 30, 14, 25}, K = 3
Output: 19

Approach:
The brute-force solution will be to try all the possible partitions and take the minimum overall. Although this solution is exponential in time. In the recursive solution, there are many overlapping sub-problems that can be optimised using dynamic programming.

So, We can form a basic recursive formula and that computes every possible solution and finds the best possible solution. We can see that the recursive solution has many overlapping sub-problems we can reduce the complexity using Dynamic programming.

Recursive formula:
F(i, K) = { min of all values such that j < i [ max(Arr[i..j]) * (i – j + 1) – Sum(A[i…j] ] } + F(j, K-1)

The bottom-up approach can be used to compute the values of sub-problems first and store them.

Here dp[i][j] defines the minimum value that can be obtained if the array is starting from index i and have j partition.

So, the answer to the problems will be dp[0][K], array starting at 0 and having K partitions.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the above approach
  
#include <bits/stdc++.h>
using namespace std;
  
// Function to divide an array into k
// parts such that the sum of difference
// of every element with the maximum element
// of that part is minimum
int divideArray(int arr[], int n, int k)
{
    // Dp to store the values
    int dp[500][500] = { 0 };
  
    k -= 1;
  
    // Fill up the dp table
    for (int i = n - 1; i >= 0; i--) {
        for (int j = 0; j <= k; j++) {
            // Intitilize maximum value
            dp[i][j] = INT_MAX;
  
            // Max element and the sum
            int max_ = -1, sum = 0;
  
            // Run a loop from i to n
            for (int l = i; l < n; l++) {
                // Find the maximum number
                // from i to l and the sum
                // from i to l
                max_ = max(max_, arr[l]);
                sum += arr[l];
  
                // Find the sum of difference
                // of every element with the
                // maximum element
                int diff = (l - i + 1) * max_ - sum;
  
                // If the array can be divided
                if (j > 0)
                    dp[i][j]
                        = min(dp[i][j],
                              diff + dp[l + 1][j - 1]);
                else
                    dp[i][j] = diff;
            }
        }
    }
  
    // Returns the minimum sum
    // in K parts
    return dp[0][k];
}
  
// Driver code
int main()
{
    int arr[] = { 2, 9, 5, 4, 8, 3, 6 };
    int n = sizeof(arr) / sizeof(int);
    int k = 2;
  
    cout << divideArray(arr, n, k) << "\n";
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the above approach 
class GFG
{
      
    // Function to divide an array into k 
    // parts such that the sum of difference 
    // of every element with the maximum element 
    // of that part is minimum 
    static int divideArray(int arr[], int n, int k) 
    
        // Dp to store the values 
        int dp[][] = new int[500][500]; 
          
        int i, j;
          
        for(i = 0; i < 500; i++)
            for(j = 0; j < 500; j++)
                dp[i][j] = 0;
                  
        k -= 1
      
        // Fill up the dp table 
        for (i = n - 1; i >= 0; i--) 
        
            for (j = 0; j <= k; j++) 
            
                  
                // Intitilize maximum value 
                dp[i][j] = Integer.MAX_VALUE; 
      
                // Max element and the sum 
                int max_ = -1, sum = 0
      
                // Run a loop from i to n 
                for (int l = i; l < n; l++)
                
                    // Find the maximum number 
                    // from i to l and the sum 
                    // from i to l 
                    max_ = Math.max(max_, arr[l]); 
                    sum += arr[l]; 
      
                    // Find the sum of difference 
                    // of every element with the 
                    // maximum element 
                    int diff = (l - i + 1) * max_ - sum; 
      
                    // If the array can be divided 
                    if (j > 0
                        dp[i][j] = Math.min(dp[i][j], diff + 
                                            dp[l + 1][j - 1]); 
                    else
                        dp[i][j] = diff; 
                
            
        
      
        // Returns the minimum sum 
        // in K parts 
        return dp[0][k]; 
    
      
    // Driver code 
    public static void main (String[] args)
    
        int arr[] = { 2, 9, 5, 4, 8, 3, 6 }; 
        int n = arr.length; 
        int k = 2
      
        System.out.println(divideArray(arr, n, k)); 
    
}
  
// This code is contributed by AnkitRai01

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the above approach
  
# Function to divide an array into k
# parts such that the summ of difference
# of every element with the maximum element
# of that part is minimum
def divideArray(arr, n, k):
      
    # Dp to store the values
    dp = [[0 for i in range(500)] 
             for i in range(500)]
  
    k -= 1
  
    # Fill up the dp table
    for i in range(n - 1, -1, -1):
        for j in range(0, k + 1):
              
            # Intitilize maximum value
            dp[i][j] = 10**9
  
            # Max element and the summ
            max_ = -1
            summ = 0
  
            # Run a loop from i to n
            for l in range(i, n):
                  
                # Find the maximum number
                # from i to l and the summ
                # from i to l
                max_ = max(max_, arr[l])
                summ += arr[l]
  
                # Find the summ of difference
                # of every element with the
                # maximum element
                diff = (l - i + 1) * max_ - summ
  
                # If the array can be divided
                if (j > 0):
                    dp[i][j]= min(dp[i][j], diff + 
                                  dp[l + 1][j - 1])
                else:
                    dp[i][j] = diff
  
    # Returns the minimum summ
    # in K parts
    return dp[0][k]
  
# Driver code
arr = [2, 9, 5, 4, 8, 3, 6]
n = len(arr)
k = 2
  
print(divideArray(arr, n, k))
  
# This code is contributed by Mohit Kumar

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# implementation of above approach
using System;
  
class GFG
{
      
    // Function to divide an array into k 
    // parts such that the sum of difference 
    // of every element with the maximum element 
    // of that part is minimum 
    static int divideArray(int []arr, int n, int k) 
    
        // Dp to store the values 
        int [,]dp = new int[500, 500]; 
          
        int i, j;
          
        for(i = 0; i < 500; i++)
            for(j = 0; j < 500; j++)
                dp[i, j] = 0;
                  
        k -= 1; 
      
        // Fill up the dp table 
        for (i = n - 1; i >= 0; i--) 
        
            for (j = 0; j <= k; j++) 
            
                  
                // Intitilize maximum value 
                dp[i, j] = int.MaxValue; 
      
                // Max element and the sum 
                int max_ = -1, sum = 0; 
      
                // Run a loop from i to n 
                for (int l = i; l < n; l++)
                
                    // Find the maximum number 
                    // from i to l and the sum 
                    // from i to l 
                    max_ = Math.Max(max_, arr[l]); 
                    sum += arr[l]; 
      
                    // Find the sum of difference 
                    // of every element with the 
                    // maximum element 
                    int diff = (l - i + 1) * max_ - sum; 
      
                    // If the array can be divided 
                    if (j > 0) 
                        dp[i, j] = Math.Min(dp[i, j], diff + 
                                            dp[l + 1, j - 1]); 
                    else
                        dp[i, j] = diff; 
                
            
        
      
        // Returns the minimum sum 
        // in K parts 
        return dp[0, k]; 
    
      
    // Driver code 
    public static void Main (String[] args)
    
        int []arr = { 2, 9, 5, 4, 8, 3, 6 }; 
        int n = arr.Length; 
        int k = 2; 
      
        Console.WriteLine(divideArray(arr, n, k)); 
    
}
  
// This code is contributed by 29AjayKumar

chevron_right


Output:

19


My Personal Notes arrow_drop_up

Second year Department of Information Technology Jadavpur University

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.