我们必须绘制长度为 {A1, A2, .. An} 的 n 块板。有 k 个油漆工可用,每个油漆工需要 1 个单位时间来绘制 1 个单位的板。问题是在任何画家只会绘制板的连续部分的约束下找到完成这项工作的最短时间,例如板 {2, 3, 4} 或仅板 {1} 或什么但不涂板 {2, 4, 5}。
例子 :
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.
在上一篇文章中,我们讨论了一种基于动态规划的方法,其时间复杂度为和额外的空间。
在这篇文章中,我们将研究使用二分搜索的更有效方法。我们知道二分查找的不变量有两个主要部分:
* 目标值将始终在搜索范围内。
* 搜索范围将在每个循环中减小,以便可以达到终止。
我们也知道这个范围内的值必须按顺序排列。这里我们的目标值是板子优化分配中连续部分的最大总和。现在我们如何为此应用二分搜索?我们可以确定目标值的可能从低到高的范围,并缩小搜索范围以获得最佳分配。
我们可以看到,这个范围内可能的最高值是数组中所有元素的总和,当我们为板的所有部分分配 1 个画家时就会发生这种情况。此范围的最低可能值是数组 max 的最大值,因为在此分配中,我们可以将 max 分配给一个画家并将其他部分划分为使得它们的成本小于或等于 max 并尽可能接近到最大。现在,如果我们考虑在上述场景中使用 x 个画家,很明显随着范围内的值增加,x 的值减小,反之亦然。由此我们可以找到x=k时的目标值,并使用辅助函数找到x,当给定油漆工可以绘制的最大截面长度时所需的最少油漆工数量。
C++
// CPP program for painter's partition problem
#include
using namespace std;
// return the maximum element from the array
int getMax(int arr[], int n)
{
int max = INT_MIN;
for (int i = 0; i < n; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
// return the sum of the elements in the array
int getSum(int arr[], int n)
{
int total = 0;
for (int i = 0; i < n; i++)
total += arr[i];
return total;
}
// find minimum required painters for given maxlen
// which is the maximum length a painter can paint
int numberOfPainters(int arr[], int n, int maxLen)
{
int total = 0, numPainters = 1;
for (int i = 0; i < n; i++) {
total += arr[i];
if (total > maxLen) {
// for next count
total = arr[i];
numPainters++;
}
}
return numPainters;
}
int partition(int arr[], int n, int k)
{
int lo = getMax(arr, n);
int hi = getSum(arr, n);
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int requiredPainters = numberOfPainters(arr, n, mid);
// find better optimum in lower half
// here mid is included because we
// may not get anything better
if (requiredPainters <= k)
hi = mid;
// find better optimum in upper half
// here mid is excluded because it gives
// required Painters > k, which is invalid
else
lo = mid + 1;
}
// required
return lo;
}
// driver function
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 3;
cout << partition(arr, n, k) << endl;
return 0;
}
Java
// Java Program for painter's partition problem
import java.util.*;
import java.io.*;
class GFG {
// return the maximum element from the array
static int getMax(int arr[], int n)
{
int max = Integer.MIN_VALUE;
for (int i = 0; i < n; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
// return the sum of the elements in the array
static int getSum(int arr[], int n)
{
int total = 0;
for (int i = 0; i < n; i++)
total += arr[i];
return total;
}
// find minimum required painters for given maxlen
// which is the maximum length a painter can paint
static int numberOfPainters(int arr[], int n, int maxLen)
{
int total = 0, numPainters = 1;
for (int i = 0; i < n; i++) {
total += arr[i];
if (total > maxLen) {
// for next count
total = arr[i];
numPainters++;
}
}
return numPainters;
}
static int partition(int arr[], int n, int k)
{
int lo = getMax(arr, n);
int hi = getSum(arr, n);
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int requiredPainters = numberOfPainters(arr, n, mid);
// find better optimum in lower half
// here mid is included because we
// may not get anything better
if (requiredPainters <= k)
hi = mid;
// find better optimum in upper half
// here mid is excluded because it gives
// required Painters > k, which is invalid
else
lo = mid + 1;
}
// required
return lo;
}
// Driver code
public static void main(String args[])
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// 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 painter's partition problem
# Find minimum required painters for given maxlen
# which is the maximum length a painter can paint
def numberOfPainters(arr, n, maxLen):
total = 0
numPainters = 1
for i in arr:
total += i
if (total > maxLen):
# for next count
total = i
numPainters += 1
return numPainters
def partition(arr, n, k):
lo = max(arr)
hi = sum(arr)
while (lo < hi):
mid = lo + (hi - lo) / 2
requiredPainters = numberOfPainters(arr, n, mid)
# find better optimum in lower half
# here mid is included because we
# may not get anything better
if (requiredPainters <= k):
hi = mid
# find better optimum in upper half
# here mid is excluded because it gives
# required Painters > k, which is invalid
else:
lo = mid + 1
# required
return lo
# Driver code
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
n = len(arr)
k = 3
print(int(partition(arr, n, k)))
C#
// C# Program for painter's
// partition problem
using System;
class GFG {
// return the maximum
// element from the array
static int getMax(int[] arr, int n)
{
int max = int.MinValue;
for (int i = 0; i < n; i++)
if (arr[i] > max)
max = arr[i];
return max;
}
// return the sum of the
// elements in the array
static int getSum(int[] arr, int n)
{
int total = 0;
for (int i = 0; i < n; i++)
total += arr[i];
return total;
}
// find minimum required
// painters for given
// maxlen which is the
// maximum length a painter
// can paint
static int numberOfPainters(int[] arr,
int n, int maxLen)
{
int total = 0, numPainters = 1;
for (int i = 0; i < n; i++) {
total += arr[i];
if (total > maxLen) {
// for next count
total = arr[i];
numPainters++;
}
}
return numPainters;
}
static int partition(int[] arr,
int n, int k)
{
int lo = getMax(arr, n);
int hi = getSum(arr, n);
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int requiredPainters = numberOfPainters(arr, n, mid);
// find better optimum in lower
// half here mid is included
// because we may not get
// anything better
if (requiredPainters <= k)
hi = mid;
// find better optimum in upper
// half here mid is excluded
// because it gives required
// Painters > k, which is invalid
else
lo = mid + 1;
}
// required
return lo;
}
// Driver code
static public void Main()
{
int[] arr = { 1, 2, 3, 4, 5,
6, 7, 8, 9 };
// Calculate size of array.
int n = arr.Length;
int k = 3;
Console.WriteLine(partition(arr, n, k));
}
}
// This code is contributed by ajit
PHP
$max)
$max = $arr[$i];
return $max;
}
// return the sum of the
// elements in the array
function getSum($arr, $n)
{
$total = 0;
for ($i = 0; $i < $n; $i++)
$total += $arr[$i];
return $total;
}
// find minimum required painters
// for given maxlen which is the
// maximum length a painter can paint
function numberOfPainters($arr, $n,
$maxLen)
{
$total = 0; $numPainters = 1;
for ($i = 0; $i < $n; $i++)
{
$total += $arr[$i];
if ($total > $maxLen)
{
// for next count
$total = $arr[$i];
$numPainters++;
}
}
return $numPainters;
}
function partition($arr, $n, $k)
{
$lo = getMax($arr, $n);
$hi = getSum($arr, $n);
while ($lo < $hi)
{
$mid = $lo + ($hi - $lo) / 2;
$requiredPainters =
numberOfPainters($arr,
$n, $mid);
// find better optimum in
// lower half here mid is
// included because we may
// not get anything better
if ($requiredPainters <= $k)
$hi = $mid;
// find better optimum in
// upper half here mid is
// excluded because it
// gives required Painters > k,
// which is invalid
else
$lo = $mid + 1;
}
// required
return floor($lo);
}
// Driver Code
$arr = array(1, 2, 3,
4, 5, 6,
7, 8, 9);
$n = sizeof($arr);
$k = 3;
echo partition($arr, $n, $k), "\n";
// This code is contributed by ajit
?>
Javascript
输出 :
17
为了更好地理解,请用纸笔跟踪程序中给出的示例。
上述方法的时间复杂度为 .
参考:
https://articles.leetcode.com/the-painters-partition-problem-part-ii/
https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/
被问到:谷歌,Codenation。