一、题目 项目组共有N个开发人员,项目经理接到了M个独立的需求,每个需求的工作量不同,且每个需求只能由一个开发人员独立完成,不能多人合作。假定各个需求直接无任何先后依赖关系,请设计算法帮助项目经理进行工作安排,使整个项目能用最少的时间交付。
二、输入 第一行输入为M个需求的工作量,单位为天,用逗号隔开。
例如:X1 X2 X3 …. Xm 。表示共有M个需求,每个需求的工作量分别为X1天,X2天……Xm天。 其中0<M<30;0<Xm<200
第二行输入为项目组人员数量N
三、输出 最快完成所有工作的天数
四、示例 1 2 3 4 5 6 输入: 6 2 7 7 9 3 2 1 3 11 4 2 输出: 28
说明:共有两位员工,其中一位分配需求 6 2 7 7 3 2 1共需要28天完成,另一位分配需求 9 3 11 4 共需要27天完成,故完成所有工作至少需要28天。
五、题解
问题解有单调性,在一个区间范围内。考虑二分法找可行解和最优解
验证解的正确性时尝试过贪心和动态规划,都没有得到最优解。暴搜 DFS可以找到最优解,但是明显效率不高
5.1 Java 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 package org.stone.study.algo.ex202412;import java.util.Arrays;import java.util.Scanner;public class ProjectScheduler { public static void main (String[] args) { Scanner sc = new Scanner (System.in); int [] workLoads = Arrays.stream(sc.nextLine().split(" " )).mapToInt(Integer::parseInt).toArray(); int n = Integer.parseInt(sc.nextLine()); int ans = new ProjectScheduler ().minCompletionTimeByDFS(workLoads, n); System.out.println(ans); } public int minCompletionTimeByDFS (int [] workLoads, int n) { int left = Arrays.stream(workLoads).max().orElse(0 ); int right = Arrays.stream(workLoads).sum(); while (left < right) { int mid = left + (right - left) / 2 ; if (check(workLoads, mid, n)) { right = mid; } else { left = mid + 1 ; } } return left; } public boolean check (int [] workLoads, int limit, int n) { int [] allocates = new int [n]; return dfs(workLoads, 0 , limit, allocates); } private boolean dfs (int [] workLoads, int i, int limit, int [] allocates) { if (i == workLoads.length) { return true ; } int curWorkLoad = workLoads[i]; for (int j = 0 ; j < allocates.length; j++) { if (allocates[j] + curWorkLoad <= limit) { allocates[j] += curWorkLoad; if (dfs(workLoads, i + 1 , limit, allocates)) { return true ; } allocates[j] -= curWorkLoad; } } return false ; } public int minCompletionTimeByDP (int [] tasks, int n) { int m = tasks.length; int [] prefixSum = new int [m + 1 ]; for (int i = 0 ; i < m; i++) { prefixSum[i + 1 ] = prefixSum[i] + tasks[i]; } int [][] dp = new int [m + 1 ][n + 1 ]; for (int [] row : dp) { Arrays.fill(row, Integer.MAX_VALUE); } for (int i = 0 ; i <= m; i++) { dp[i][1 ] = prefixSum[i]; } for (int j = 2 ; j <= n; j++) { for (int i = 1 ; i <= m; i++) { for (int k = 0 ; k < i; k++) { int currentMaxWorkload = Math.max(dp[k][j - 1 ], prefixSum[i] - prefixSum[k]); dp[i][j] = Math.min(dp[i][j], currentMaxWorkload); } } } return dp[m][n]; } }
5.2 Python实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 def min_time_to_complete (tasks, n ): left, right = max (tasks), sum (tasks) while left < right: mid = (left + right) // 2 if check(tasks, n, mid): right = mid else : left = mid + 1 return left def check (tasks, n, limit ): allocated = [0 ] * (n) return dfs(tasks, 0 , limit, allocated) def dfs (tasks, i, limit, allocated ): if i == len (tasks): return True cur_workload = tasks[i] for j in range (n): if allocated[j] + cur_workload <= limit: allocated[j] += cur_workload if dfs(tasks, i + 1 , limit, allocated): return True allocated[j] -= cur_workload return False if __name__ == '__main__' : tasks = list (map (int , input ().split())) n = int (input ()) print (min_time_to_complete(tasks, n))