我们必须绘制n个长度为{A1,A2,.. An}的木板。有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/cn/community/data-science/data-science-tutorials/binary-search/
询问:Google,Codenation。
如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。