Related Articles

# The painter’s partition problem

• Difficulty Level : Hard
• Last Updated : 21 May, 2021

We have to paint n boards of length {A1, A2…An}. There are k painters available and each takes 1 unit time to paint 1 unit of board. The problem is to find the minimum time to get
this job done under the constraints that any painter will only paint continuous sections of boards, say board {2, 3, 4} or only board {1} or nothing but not board {2, 4, 5}.

Examples:

```Input : k = 2, A = {10, 10, 10, 10}
Output : 20.
Here we can divide the boards into 2
equal sized partitions, so each painter
gets 20 units of board and the total
time taken is 20.

Input : k = 2, A = {10, 20, 30, 40}
Output : 60.
Here we can divide first 3 boards for
one painter and the last board for
second painter.```

From the above examples, it is obvious that the strategy of dividing the boards into k equal partitions won’t work for all the cases. We can observe that the problem can be broken down into: Given an array A of non-negative integers and a positive integer k, we have to divide A into k of fewer partitions such that the maximum sum of the elements in a partition, overall partitions is minimized. So for the second example above, possible divisions are:

* One partition: so time is 100.

* Two partitions: (10) & (20, 30, 40), so time is 90. Similarly we can put the first divider
after 20 (=> time 70) or 30 (=> time 60); so this means the minimum time: (100, 90, 70, 60) is 60.
A brute force solution is to consider all possible set of contiguous partitions and calculate the maximum sum partition in each case and return the minimum of all these cases.

1) Optimal Substructure:
We can implement the naive solution using recursion with the following optimal substructure property:
Assuming that we already have k-1 partitions in place (using k-2 dividers), we now have to put the k-1 th divider to get k partitions.
How can we do this? We can put the k-1 th divider between the i th and i+1 th element where i = 1 to n. Please note that putting it before the first element is the same as putting it after the last element.
The total cost of this arrangement can be calculated as the maximum of the following:
a) The cost of the last partition: sum(Ai..An), where the k-1 th divider is
before element i.
b) The maximum cost of any partition already formed to the left of the k-1 th divider.
Here a) can be found out using a simple helper function to calculate sum
of elements between two indices in the array. How to find out b) ?
We can observe that b) actually is to place the k-2 separators as fairly as
possible, so it is a subproblem of the given problem. Thus we can write the optimal
substructure property as the following recurrence relation: Following is the implementation of the above recursive equation:

## C++

 `// CPP program for The painter's partition problem``#include ``#include ``using` `namespace` `std;` `// function to calculate sum between two indices``// in array``int` `sum(``int` `arr[], ``int` `from, ``int` `to)``{``    ``int` `total = 0;``    ``for` `(``int` `i = from; i <= to; i++)``        ``total += arr[i];``    ``return` `total;``}` `// for n boards and k partitions``int` `partition(``int` `arr[], ``int` `n, ``int` `k)``{``    ``// base cases   ``    ``if` `(k == 1) ``// one partition``        ``return` `sum(arr, 0, n - 1);   ``    ``if` `(n == 1)  ``// one board``        ``return` `arr;` `    ``int` `best = INT_MAX;` `    ``// find minimum of all possible maximum``    ``// k-1 partitions to the left of arr[i],``    ``// with i elements, put k-1 th divider``    ``// between arr[i-1] & arr[i] to get k-th``    ``// partition``    ``for` `(``int` `i = 1; i <= n; i++)``        ``best = min(best, max(partition(arr, i, k - 1),``                                ``sum(arr, i, n - 1)));` `    ``return` `best;``}` `int` `main()``{``    ``int` `arr[] = { 10, 20, 60, 50, 30, 40 };``    ``int` `n = ``sizeof``(arr) / ``sizeof``(arr);``    ``int` `k = 3;``    ``cout << partition(arr, n, k) << endl;` `    ``return` `0;``}`

## Java

 `// Java Program for The painter's partition problem``import` `java.util.*;``import` `java.io.*;` `class` `GFG``{``// function to calculate sum between two indices``// in array``static` `int` `sum(``int` `arr[], ``int` `from, ``int` `to)``{``    ``int` `total = ``0``;``    ``for` `(``int` `i = from; i <= to; i++)``        ``total += arr[i];``    ``return` `total;``}`` ` `// for n boards and k partitions``static` `int` `partition(``int` `arr[], ``int` `n, ``int` `k)``{``    ``// base cases   ``    ``if` `(k == ``1``) ``// one partition``        ``return` `sum(arr, ``0``, n - ``1``);   ``    ``if` `(n == ``1``)  ``// one board``        ``return` `arr[``0``];`` ` `    ``int` `best = Integer.MAX_VALUE;`` ` `    ``// find minimum of all possible maximum``    ``// k-1 partitions to the left of arr[i],``    ``// with i elements, put k-1 th divider``    ``// between arr[i-1] & arr[i] to get k-th``    ``// partition``    ``for` `(``int` `i = ``1``; i <= n; i++)``        ``best = Math.min(best, Math.max(partition(arr, i, k - ``1``),``                                ``sum(arr, i, n - ``1``)));`` ` `    ``return` `best;``}` `// Driver code``public` `static` `void` `main(String args[])``{`` ``int` `arr[] = { ``10``, ``20``, ``60``, ``50``, ``30``, ``40` `};`` ` `    ``// Calculate size of array.``    ``int` `n = arr.length;``        ``int` `k = ``3``;`` ``System.out.println(partition(arr, n, k));``}``}` `// This code is contributed by Sahil_Bansall`

## Python3

 `# Python program for The painter's``# partition problem function to``# calculate sum between two indices``# in array``def` `sum``(arr, frm, to):``    ``total ``=` `0``;``    ``for` `i ``in` `range``(frm, to ``+` `1``):``        ``total ``+``=` `arr[i]``    ``return` `total``    ` `# for n boards and k partitions``def` `partition(arr, n, k):``    ` `    ``# base cases``    ``if` `k ``=``=` `1``: ``# one partition``        ``return` `sum``(arr, ``0``, n ``-` `1``)``    ``if` `n ``=``=` `1``: ``# one board``        ``return` `arr[``0``]``    ``best ``=` `100000000``    ` `    ``# find minimum of all possible ``    ``# maximum k-1 partitions to ``    ``# the left of arr[i], with i``    ``# elements, put k-1 th divider``    ``# between arr[i-1] & arr[i] to``    ``# get k-th partition``    ``for` `i ``in` `range``(``1``, n ``+` `1``):``        ``best ``=` `min``(best,``               ``max``(partition(arr, i, k ``-` `1``),``                         ``sum``(arr, i, n ``-` `1``)))``    ``return` `best``    ` `# Driver Code``arr ``=` `[``10``, ``20``, ``60``, ``50``, ``30``, ``40` `]``n ``=` `len``(arr)``k ``=` `3``print``(partition(arr, n, k))` `# This code is contributed``# by sahilshelangia`

## C#

 `// C# Program for The painter's partition problem``using` `System;` `class` `GFG {``    ` `// function to calculate sum``// between two indices in array``static` `int` `sum(``int` `[]arr, ``int` `from``, ``int` `to)``{``    ``int` `total = 0;``    ``for` `(``int` `i = ``from``; i <= to; i++)``        ``total += arr[i];``    ``return` `total;``}` `// for n boards and k partitions``static` `int` `partition(``int` `[]arr, ``int` `n, ``int` `k)``{``    ``// base cases``    ``if` `(k == 1) ``// one partition``        ``return` `sum(arr, 0, n - 1);``        ` `    ``if` `(n == 1) ``// one board``        ``return` `arr;` `    ``int` `best = ``int``.MaxValue;` `    ``// find minimum of all possible maximum``    ``// k-1 partitions to the left of arr[i],``    ``// with i elements, put k-1 th divider``    ``// between arr[i-1] & arr[i] to get k-th``    ``// partition``    ``for` `(``int` `i = 1; i <= n; i++)``        ``best = Math.Min(best, Math.Max(partition(arr, i, k - 1),``                                           ``sum(arr, i, n - 1)));` `    ``return` `best;``}` `// Driver code``public` `static` `void` `Main()``{``    ``int` `[]arr = {10, 20, 60, 50, 30, 40};` `    ``// Calculate size of array.``    ``int` `n = arr.Length;``    ``int` `k = 3;``    ` `    ``// Function calling``    ``Console.WriteLine(partition(arr, n, k));``}``}` `// This code is contributed by vt_m`

## PHP

 ``

## Javascript

 ``

Output :

`90`

The time complexity of the above solution is exponential.

2) Overlapping subproblems:
Following is the partial recursion tree for T(4, 3) in above equation.

```      T(4, 3)
/    /    \ ..
T(1, 2)  T(2, 2) T(3, 2)
/..      /..
T(1, 1)    T(1, 1)```

We can observe that many subproblems like T(1, 1) in the above problem are being solved again and again. Because of these two properties of this problem, we can solve it using dynamic programming, either by top down memoized method or bottom up
tabular method. Following is the bottom up tabular implementation:

## C++

 `// A DP based CPP program for painter's partition problem``#include ``#include ``using` `namespace` `std;` `// function to calculate sum between two indices``// in array``int` `sum(``int` `arr[], ``int` `from, ``int` `to)``{``    ``int` `total = 0;``    ``for` `(``int` `i = from; i <= to; i++)``        ``total += arr[i];``    ``return` `total;``}` `// bottom up tabular dp``int` `findMax(``int` `arr[], ``int` `n, ``int` `k)``{``    ``// initialize table``    ``int` `dp[k + 1][n + 1] = { 0 };` `    ``// base cases``    ``// k=1``    ``for` `(``int` `i = 1; i <= n; i++)``        ``dp[i] = sum(arr, 0, i - 1);` `    ``// n=1``    ``for` `(``int` `i = 1; i <= k; i++)``        ``dp[i] = arr;` `    ``// 2 to k partitions``    ``for` `(``int` `i = 2; i <= k; i++) { ``// 2 to n boards``        ``for` `(``int` `j = 2; j <= n; j++) {` `            ``// track minimum``            ``int` `best = INT_MAX;` `            ``// i-1 th separator before position arr[p=1..j]``            ``for` `(``int` `p = 1; p <= j; p++)``                ``best = min(best, max(dp[i - 1][p],``                              ``sum(arr, p, j - 1)));      ` `            ``dp[i][j] = best;``        ``}``    ``}` `    ``// required``    ``return` `dp[k][n];``}` `// driver function``int` `main()``{``    ``int` `arr[] = { 10, 20, 60, 50, 30, 40 };``    ``int` `n = ``sizeof``(arr) / ``sizeof``(arr);``    ``int` `k = 3;``    ``cout << findMax(arr, n, k) << endl;``    ``return` `0;``}`

## Java

 `// A DP based Java program for``// painter's partition problem``import` `java.util.*;``import` `java.io.*;` `class` `GFG``{``// function to calculate sum between two indices``// in array``static` `int` `sum(``int` `arr[], ``int` `from, ``int` `to)``{``    ``int` `total = ``0``;``    ``for` `(``int` `i = from; i <= to; i++)``        ``total += arr[i];``    ``return` `total;``}`` ` `// bottom up tabular dp``static` `int` `findMax(``int` `arr[], ``int` `n, ``int` `k)``{``    ``// initialize table``    ``int` `dp[][] = ``new` `int``[k+``1``][n+``1``];`` ` `    ``// base cases``    ``// k=1``    ``for` `(``int` `i = ``1``; i <= n; i++)``        ``dp[``1``][i] = sum(arr, ``0``, i - ``1``);`` ` `    ``// n=1``    ``for` `(``int` `i = ``1``; i <= k; i++)``        ``dp[i][``1``] = arr[``0``];`` ` `    ``// 2 to k partitions``    ``for` `(``int` `i = ``2``; i <= k; i++) { ``// 2 to n boards``        ``for` `(``int` `j = ``2``; j <= n; j++) {`` ` `            ``// track minimum``            ``int` `best = Integer.MAX_VALUE;`` ` `            ``// i-1 th separator before position arr[p=1..j]``            ``for` `(``int` `p = ``1``; p <= j; p++)``                ``best = Math.min(best, Math.max(dp[i - ``1``][p],``                              ``sum(arr, p, j - ``1``)));      `` ` `            ``dp[i][j] = best;``        ``}``    ``}`` ` `    ``// required``    ``return` `dp[k][n];``}` `// Driver code``public` `static` `void` `main(String args[])``{`` ``int` `arr[] = { ``10``, ``20``, ``60``, ``50``, ``30``, ``40` `};`` ` `    ``// Calculate size of array.``    ``int` `n = arr.length;``        ``int` `k = ``3``;`` ``System.out.println(findMax(arr, n, k));``}``}` `// This code is contributed by Sahil_Bansall`

## Python3

 `# A DP based Python3 program for``# painter's partition problem` `# function to calculate sum between``# two indices in list``def` `sum``(arr, start, to):``    ``total ``=` `0``    ``for` `i ``in` `range``(start, to ``+` `1``):``        ``total ``+``=` `arr[i]``    ``return` `total` `# bottom up tabular dp``def` `findMax(arr, n, k):``    ` `    ``# initialize table``    ``dp ``=` `[[``0` `for` `i ``in` `range``(n ``+` `1``)]``             ``for` `j ``in` `range``(k ``+` `1``)]` `    ``# base cases``    ``# k=1``    ``for` `i ``in` `range``(``1``, n ``+` `1``):``        ``dp[``1``][i] ``=` `sum``(arr, ``0``, i ``-` `1``)` `    ``# n=1``    ``for` `i ``in` `range``(``1``, k ``+` `1``):``        ``dp[i][``1``] ``=` `arr[``0``]` `    ``# 2 to k partitions``    ``for` `i ``in` `range``(``2``, k ``+` `1``): ``# 2 to n boards``        ``for` `j ``in` `range``(``2``, n ``+` `1``):``            ` `            ``# track minimum``            ``best ``=` `100000000``            ` `            ``# i-1 th separator before position arr[p=1..j]``            ``for` `p ``in` `range``(``1``, j ``+` `1``):``                ``best ``=` `min``(best, ``max``(dp[i ``-` `1``][p],``                                 ``sum``(arr, p, j ``-` `1``)))    ` `            ``dp[i][j] ``=` `best` `    ``# required``    ``return` `dp[k][n]` `# Driver Code``arr ``=` `[``10``, ``20``, ``60``, ``50``, ``30``, ``40``]``n ``=` `len``(arr)``k ``=` `3``print``(findMax(arr, n, k))` `# This code is contributed by ashutosh450`

## C#

 `// A DP based C# program for``// painter's partition problem``using` `System;` `class` `GFG {``    ` `// function to calculate sum between``// two indices in array``static` `int` `sum(``int` `[]arr, ``int` `from``, ``int` `to)``{``    ``int` `total = 0;``    ``for` `(``int` `i = ``from``; i <= to; i++)``        ``total += arr[i];``    ``return` `total;``}` `// bottom up tabular dp``static` `int` `findMax(``int` `[]arr, ``int` `n, ``int` `k)``{``    ``// initialize table``    ``int` `[,]dp = ``new` `int``[k+1,n+1];` `    ``// base cases``    ``// k=1``    ``for` `(``int` `i = 1; i <= n; i++)``        ``dp[1,i] = sum(arr, 0, i - 1);` `    ``// n=1``    ``for` `(``int` `i = 1; i <= k; i++)``        ``dp[i,1] = arr;` `    ``// 2 to k partitions``    ``for` `(``int` `i = 2; i <= k; i++) { ``// 2 to n boards``        ``for` `(``int` `j = 2; j <= n; j++) {` `            ``// track minimum``            ``int` `best = ``int``.MaxValue;` `            ``// i-1 th separator before position arr[p=1..j]``            ``for` `(``int` `p = 1; p <= j; p++)``                ``best = Math.Min(best, Math.Max(dp[i - 1,p],``                                      ``sum(arr, p, j - 1)));` `            ``dp[i,j] = best;``        ``}``    ``}` `    ``// required``    ``return` `dp[k,n];``}` `// Driver code``public` `static` `void` `Main()``{``    ``int` `[]arr = {10, 20, 60, 50, 30, 40};` `    ``// Calculate size of array.``    ``int` `n = arr.Length;``    ``int` `k = 3;``    ``Console.WriteLine(findMax(arr, n, k));``}``}` `// This code is contributed by vt_m`

## PHP

 ``

## Javascript

 ``

Output:

`90`

Optimizations:

1) The time complexity of the above program is . It can be easily brought down to by precomputing the cumulative sums in an array thus avoiding repeated calls to the sum function:

## C++

 `int` `sum[n+1] = {0};` ` ``// sum from 1 to i elements of arr`` ``for` `(``int` `i = 1; i <= n; i++)``   ``sum[i] = sum[i-1] + arr[i-1];` ` ``for` `(``int` `i = 1; i <= n; i++)``   ``dp[i] = sum[i];` `and ``using` `it to calculate the result as:``best = min(best, max(dp[i-1][p], sum[j] - sum[p]));`

## Java

 `int` `sum[] = ``new` `int``[n+``1``];``  ` ` ``// sum from 1 to i elements of arr`` ``for` `(``int` `i = ``1``; i <= n; i++)``   ``sum[i] = sum[i-``1``] + arr[i-``1``];``  ` ` ``for` `(``int` `i = ``1``; i <= n; i++)``   ``dp[``1``][i] = sum[i];``  ` `and using it to calculate the result as:``best = Math.min(best, Math.max(dp[i-``1``][p], sum[j] - sum[p]));` `// This code is contributed by divyesh072019.`

## C#

 `int``[] sum = ``new` `int``[n+1];`` ` ` ``// sum from 1 to i elements of arr`` ``for` `(``int` `i = 1; i <= n; i++)``   ``sum[i] = sum[i-1] + arr[i-1];`` ` ` ``for` `(``int` `i = 1; i <= n; i++)``   ``dp[1,i] = sum[i];`` ` `and ``using` `it to calculate the result ``as``:``best = Math.Min(best, Math.Max(dp[i-1][p], sum[j] - sum[p]));` `// This code is contributed by divyeshrabadiya07.`

2) Though here we consider to divide A into k or fewer partitions, we can observe that
the optimal case always occurs when we divide A into exactly k partitions. So we can use:

## C++

 `for` `(``int` `i = k-1; i <= n; i++)``    ``best = min(best, max( partition(arr, i, k-1),``                            ``sum(arr, i, n-1)));`

## Java

 `for` `(``int` `i = k-``1``; i <= n; i++)``      ``best = Math.min(best, Math.max(partition(arr, i, k-``1``),``                              ``sum(arr, i, n-``1``)));` `// This code is contributed by pratham76.`

## C#

 `for``(``int` `i = k - 1; i <= n; i++)``    ``best = Math.Min(best, Math.Max(partition(arr, i, k - 1),``                                         ``sum(arr, i, n - 1)));` `// This code is contributed by rutvik_56`

## Javascript

 `for``(``var` `i = k - 1; i <= n; i++)``      ``best = Math.min(best, Math.max(partition(arr, i, k - 1),``                                           ``sum(arr, i, n - 1)));``                                           ` `// This code is contributed by Ankita saini`

and modify the other implementations accordingly.
Exercise:
Can you come up with a solution using binary search? Please refer Allocate minimum number of pages for details.
References:
https://articles.leetcode.com/the-painters-partition-problem/

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.

My Personal Notes arrow_drop_up