1723. 完成所有工作的最短时间

498 阅读3分钟

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

1723. 完成所有工作的最短时间

给你一个整数数组 jobs ,其中 jobs[i] 是完成第 i 项工作要花费的时间。

请你将这些工作分配给 k 位工人。所有工作都应该分配给工人,且每项工作只能分配给一位工人。工人的 工作时间 是完成分配给他们的所有工作花费时间的总和。请你设计一套最佳的工作分配方案,使工人的 最大工作时间 得以 最小化 。

返回分配方案中尽可能 最小 的 最大工作时间 。

示例 1:

输入:jobs = [3,2,3], k = 3 输出:3 解释:给每位工人分配一项工作,最大工作时间是 3 。 示例 2:

输入:jobs = [1,2,4,7,8], k = 2 输出:11 解释:按下述方式分配工作: 1 号工人:1、2、8(工作时间 = 1 + 2 + 8 = 11) 2 号工人:4、7(工作时间 = 4 + 7 = 11) 最大工作时间是 11 。

解题思路

1. 二分

对于最小 的 最大工作时间进行二分搜索,同时限定搜索的区间[时间最长的工作,所有工作的总时间],右边界为所有工作的总时间(一个人干完所有的活),时间最长的工作(即使在最好的情况下,也要花费这个工作的时间)

因为golang的sort.Search函数搜索的区间是[0,n),因此需要修改二分的代码

 l+ sort.Search(r-l, func(limit int) bool {
	limit+=l

2. 剪枝

				if lo+jobs[cur]==limit || load[i]==0{
					break
				}

两种情况需要剪枝 在将cur号工作分配给i号工人时,递归下去无法找到满足条件的解情况下(即bc(cur+1)为false的情况,如果是true就直接return了)

  1. 当前的工人要完成这个工作的话,刚刚等于限定的工作时间

  2. 当前工人没被分配工作(load[i]==0) 当前的工人即使分配了工作的情况下,都不能满足条件了。如果load[i]==0,就是这次不干活了,活就要给其他人干,需要的时间就更长了,那就更不可能完成任务了

3. 回溯

从大到小递归遍历每一项工作时间,在一次递归中尝试将当前工作分配给每个工人,维护一个保存工人工作时间的数组,然后开启层递归下一个工作,如果不满足条件则回溯数组,直到工作都分配完。

代码

func minimumTimeRequired(jobs []int, k int) int {

	sort.Sort(sort.Reverse(sort.IntSlice(jobs)))
	l,r:=jobs[0],0
	for _, job := range jobs {
		r+=job
	}
	return l+ sort.Search(r-l, func(limit int) bool {
	limit+=l
		load := make([]int, k)
		var bc func(cur int) bool
		bc = func(cur int) bool{
			if cur==len(jobs){
				return true
			}

			for i, lo := range load {
				if lo+jobs[cur]<=limit{
					load[i]+=jobs[cur]
					if bc(cur+1){
						return true
					}
					load[i]-=jobs[cur]
				}
				if lo+jobs[cur]==limit || load[i]==0{
					break
				}

			}
			return false

		}
       return bc(0)
	})
}