dp基础之划分型抄写书的最短时间

问题:有N本书需要抄写,每本书的页数分别为A[0]...A[N-1],现有K个抄写员。每个抄写员可以连续抄写若干本书,每个抄写员的抄写速度一样一分钟一页,问最少需要多长时间抄写完所有的树。
例:
A = [3,2,4],K = 2
最少时间为:5

分析:若一个抄写员抄写A[i...j],需要时间为A[i]+...+A[j]
    最后抄写时间取决于耗时最长的那个抄写员
问题变成,找到一种划分方式,使得分成不超过K段,并且使得最大的那段数字和最小


确定状态:假设在最优策略中最后一个抄写员抄写A[j...N-1],时间为A[j]+...A[N-1]
        z则需要知道前K-1个人抄写前j本书从A[0...j-1]的最短时间
        
子问题:原问题要求K人最短时间抄完前N本书,
    现在需要知道K-1人最短时间抄完前j本书
设:f[k][i],表示K人最短时间抄完前i本书,
        f[k][i] = min{max{f[k-1][j],                 A[j]+...+A[i-1]}}(j=0...i)
                  min{max{K-1人最短时间抄完前j本书;   第K个人抄写从A[j]...到A[i-1]本书所花费的时间 }}
                  j = i表示第K个人不抄写书
初始条件:f[0][0] = 0,f[0][1]...f[0][N] = sys.maxsize
          K(K>0)个抄写员抄写0本书需要最少时间是0
          f[K][0] = 0
计算顺序:
    f[0][0]...f[0][N]
    .
    .
    .
    f[K][0]...f[K][N]
最后答案f[K][N]
    
时间复杂度:O(N^2*K),空间复杂度O(NK),优化后达到O(N)
若K>N,则令K=N,(每本书最少需要一个人,多出来的人不用抄写)

代码及注释如下:

import sys
def copy_books(A,K):
    N = len(A)
    if N == 0:
        return 0
    if K>N:
        K= N
    f = [[sys.maxsize for i in range(N+1)] for j in range(K+1)]
    #初始条件,f[0][0] = 0,f[0][1]...f[0][N] = sys.maxsize
    f[0][0] = 0
    for k in range(1,K+1):
        #抄写员的个数k
        f[k][0] = 0
        for i in range(1,N+1):
            SUM = 0
            #K个抄写员抄写前i本书
            f[k][i] = sys.maxsize
            
#             #下面这样计算会重复计算,每次都要把A[j]+...+A[i-1]加一遍
#             for j in range(0,i+1):
#                 #f[k][i] = min{max{f[k-1][j],                 A[j]+...+A[i-1]}}(j=0...i)
#                 #如果j = i,表示不抄写书,sum(A[j:i])= 0,
#                 f[k][i] = min(f[k][i],max(f[k-1][j],sum(A[j:i])))


            #下面这样计算则不会重复计算,从后往前加,从A[i-1]加到A[j]    
            for j in range(0,i+1)[::-1]:
            
                #j是最后一个抄写员,抄写A[j...i-1]本书
                #求A[j]..A[i-1]从后往前加,避免重复计算
                #f[k][i] = min{max{f[k-1][j],                 A[j]+...+A[i-1]}}(j=0...i)
            
                f[k][i] = min(f[k][i],max(f[k-1][j],SUM))
                
                if j>=0:
                    SUM += A[j-1]
    return f[K][N]
    
A = [3,2,4]
K = 2
print(copy_books(A,K))
#结果:5

猜你喜欢

转载自blog.csdn.net/lerry13579/article/details/84197785