Painter's Partition Problem
题目描述
You have to paint N boards of length {A0, A1, A2, A3 … AN-1}.
There are K painters available and you are also given how much time a painter
takes to paint 1 unit of board. You have to get this job done as soon as
possible under the constraints that any painter will only paint contiguous
sections of board.
A - number of painters
B -
C - LIst of board length
注意是要continuous assign,这是一个非常重要的条件。
解题方法
recursion
Recursion can be utilized to solve this problem easily. Imagine that we already have (k-1) partitions in place (the left partition) and we are trying to put the last separator (the (k-1)th separator). What are the possible locations to put the last separator? It must lie somewhere between the (j-1)th and jth element, where 1 = j = n. Once we have the last separator in place, we have completed all k partitions.
def sum(C, start, end):
def partition(A, B, C):
if A == 1:
return sum(C, 0, len(C))
if len(C) == 1:
return C[0]
best = sys.maxint
for i in range(1, len(C)+1):
best = min(best, max(partition(A-1, B, C[:i]), sum(C, i, len(C))))
return best
DP
可以将recursive的方法改进为DP的方法
def findMax(A, B, k):
length = len(A)
# row - num of boards
# col - num of painters
DP = [[0 for i in range(k+1)] for j in range(length+1)]
cum = [0 for i in range(length+1)]
for i in range(1, length+1):
cum[i] = cum[i-1] + A[i-1]
for i in range(1, length+1):
DP[i][1] = cum[i]
for i in range(1, k+1):
DP[1][i] = A[0]
for i in range(2, k+1):
for j in range(2, length+1):
best = sys.maxint
for p in range(1, j+1):
best = min(best, max(M[p][i-1], cum[j] - cum[p]))
DP[i][j] = best
return DP[length][k]
二分法
我们将每个painter分配到的max load设为max_per_painter
- max_per_painter的下限是
max(C), 因为至少要能够画最长的那块板 - max_per_painter的上限是
sum(C)
可以利用二分法,不断地找到中点,求出该中点需要的painter的数量,跟限制数量 B比较,然后进行二分。
优化
我们知道C是递增的,肯定会在C的开头选取一些连续的作为第一个painter的工作量, 所以我们可以先生存一个C的cumulative sum的array,设为sum[], 找到一个index i
- sum[i]为max_per_painter的时候不满足数量要求
- sum[i+1]为max_per_painter的时候满足数量要求
这样就可以把max_per_painter的范围限制到sum[i] - sum[i+1]
Solution
class Solution:
# @param A : integer
# @param B : integer
# @param C : list of integers
# @return an integer
def paint(self, A, B, C):
start = max(C)
end = sum(C)
while start + 1 < end:
mid = start + (end-start)/2
required_num = self.getRequiredPainters(C, mid)
if required_num <= A:
end = mid
else:
start = mid + 1
if self.getRequiredPainters(C, start) <= A:
return B * start % 10000003
else:
return B * end % 10000003
def getRequiredPainters(self, l, max_per_painter):
cur_total = 0
num_painter = 1
for i in range(len(l)):
cur_total += l[i]
if cur_total > max_per_painter:
cur_total = l[i]
num_painter += 1
return num_painter