LintCode刷题——书籍复印(动态规划)
题目描述
给定n
本书,第i
本书有[i]页
。有k
个人来抄这些书。
这些书排成一行,每个人都可以索取连续一段的书。例如,一个复印机可以连续地将书从第i
册复制到第j
册,但是他不能复制第1册、第2册和第4册(没有第3册)。
他们在同一时间开始抄书,每抄一页书都要花1分钟。为了让最慢的复印机能在最早的时间完成书的分配,最好的策略是什么?
请返回最慢复印机花费的最短时间。
书籍页数总和小于等于2147483647
样例
样例 1:
输入: pages = [3, 2, 4], k = 2
输出: 5
解释: 第一个人复印前两本书, 耗时 5 分钟. 第二个人复印第三本书, 耗时 4 分钟.
样例 2:
输入: pages = [3, 2, 4], k = 3
输出: 4
解释: 三个人各复印一本书.
挑战
时间复杂度 O(nk)
标签
二分法 动态规划 二分答案
状态
dp[i][j] 表示前i个抄写员抄写前j本书籍需要的最少时间
转移方程
dp[k][i] = Math.min(dp[k][i], Math.max(dp[k - 1][j], sum));
解释:这里是先找出耗时最长的那个人所用时间,然后从耗时最长的结果中找出最小的那个时间
AC代码
1 public class Solution { 2 /** 3 * @param pages: an array of integers 4 * @param k: An integer 5 * @return: an integer 6 */ 7 public int copyBooks(int[] pages, int K) { 8 // write your code here 9 int n = pages.length; 10 if (n == 0) { 11 return 0; 12 } 13 14 // 定义状态 dp:dp[i][j] 表示前i个程序员抄前j本书需要的最少时间 15 int[][] dp = new int[K + 1][n + 1]; 16 17 // 初始化 18 dp[0][0] = 0; 19 20 for (int i = 1; i <= n; i++) { 21 // 这里的意思是,0个抄写员无论有多少本书都是抄不完的,即需要的时间无穷大 22 dp[0][i] = Integer.MAX_VALUE; 23 } 24 25 // 转移方程,这将不能抄写出来设置为无穷大,即需要很长很长时间 26 // 先考虑抄写员人数 27 for (int k = 1; k <= K; k++) { 28 // 无论多少抄写员,如果没有书,就不需要时间,即等于0 29 dp[k][0] = 0; 30 // 从1本书开始考虑 31 for (int i = 1; i <= n; i++) { 32 // 选最小,不要忘了设置为无穷大 33 dp[k][i] = Integer.MAX_VALUE; 34 int sum = 0; 35 // 枚举前i本书,从后往前,如果一开始就没有留书给第i个人,sum就初始为0 36 for (int j = i; j >= 0; j--) { 37 // 这里先找出耗时最长的那个人所用时间,然后从耗时最长的结果中找出最小的那个时间 38 dp[k][i] = Math.min(dp[k][i], Math.max(dp[k - 1][j], sum)); 39 if (j > 0) { 40 sum += pages[j - 1]; 41 } 42 } 43 } 44 } 45 46 return dp[K][n]; 47 } 48 }