給你一個整數數組 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了)
-
當前的工人要完成這個工作的話,剛剛等于限定的工作時間
-
當前工人沒被分配工作(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],0for _, job := range jobs {r+=job}return l+ sort.Search(r-l, func(limit int) bool {limit+=lload := make([]int, k)var bc func(cur int) boolbc = 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)})
}