📜  画家的分区问题套装2

📅  最后修改于: 2021-04-29 05:49:05             🧑  作者: Mango

我们必须绘制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.

在上一篇文章中,我们讨论了一种基于动态编程的方法,其时间复杂度为O(K * N^2)  O(k * N)  多余的空间。
在本文中,我们将研究一种使用二进制搜索的更有效方法。我们知道二分搜索的不变量有两个主要部分:
*目标值将始终在搜索范围内。
*搜索范围将在每个循环中减小,以便可以终止。

我们也知道,该范围内的值必须按排序顺序。在这里,我们的目标值是板的最佳分配中连续部分的最大和。现在我们如何对此应用二进制搜索?我们可以将目标值的可能范围从低到高固定,并缩小搜索范围以获得最佳分配。

我们可以看到,此范围内的最大可能值是数组中所有元素的总和,当我们为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

为了更好地理解,请用笔和纸追踪程序中给出的示例。
上述方法的时间复杂度为O(N * log (sum (arr[]))
参考:
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。