1. 程式人生 > 實用技巧 >完成所有工作的最短時間

完成所有工作的最短時間

難度:困難
給你一個整數陣列 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 <= k <= jobs.length <= 12
1 <= jobs[i] <= 107

解法一:二分 + 狀態壓縮

class Solution {
public:
    int minimumTimeRequired(vector<int>& jobs, int k) {
        int n = jobs.size();
        vector<int> subsum(1 << n, 0);
        for(int i = 1; i < 1 << n; ++i){
            for(int j = 0; j < n; ++j)
                if(i & (1 << j))
                    subsum[i] += jobs[j];
        }
        int left = *max_element(jobs.begin(), jobs.end());
        int right = accumulate(jobs.begin(), jobs.end(), 0);
        while(left <= right){
            int mid = (left + right) / 2;
            if(check(jobs, k, subsum, mid))
                right = mid - 1;
            else
                left = mid + 1;
        }
        return left;
    }

    bool check(vector<int>& jobs, int k, vector<int>& subsum, int mid){
        int n = jobs.size();
        vector<long> dp(1 << n, INT_MAX);
        dp[0] = 0;
        // 從已知算未知的
        for(int mask = 0; mask < (1 << n); ++mask){
            int rem = ((1 << n) - 1) ^ mask;//剩下沒算的
            for(int sub = rem; sub; sub = (sub - 1) & rem){
                if(subsum[sub] <= mid)
                    dp[sub ^ mask] = min(dp[sub ^ mask], dp[mask] + 1);
            }
        }
        return dp[(1 << n) - 1] <= k;
    }
};