力扣周赛 1723 完成所有工作的最短时间

题意

(n) , (k) 和一个长度为 (n) 的数组 (a) ,将 (a) 分成 (k) 组,求 (k) 组里最大值的最小值

(1 le k le n le 12)

思路

这道题目的做法有很多,比较正确的做法是状压dp,也可以用模拟退火来做,也可以用贪心瞎搞 A 过去

状压dp

设 f[j][i] 表示前 j 组完成了任务集合 i 的最大值的最小值

答案就是 f[k-1][(1 << n) - 1], 考虑其转移

枚举集合 i 的子集 s

[f[j][i] = min_{sin i}(max{f[j-1][i-s], tot[s]}) ]

class Solution {
public:
    int tot[1<<13];
    int f[13][1<<13];

    int minimumTimeRequired(vector<int>& jobs, int k) {
        memset(f,0x3f,sizeof f);
        int n = jobs.size();
        for(int i = 0;i < 1 << n;i++){    
            for(int j = 0;j < n;j++){
                if((i >> j) & 1)tot[i] += jobs[j];
            }
        }
        for(int i = 0;i < (1 << n);i++)f[0][i] = tot[i];
        for(int j = 1;j < k;j++){
            for(int i = 0;i < 1 << n;i++){
                int minv = 0x3f3f3f3f;
                for(int s = i;s ;s = (s - 1) & i){
                    minv = min(minv, max(f[j-1][i - s], tot[s]));
                }
                f[j][i] = minv;
            }
        }
        return f[k-1][(1<<n) - 1];

    }
};

模拟退火

参考 HAOI2006 均分数据, 改一改就可以了 , 我的代码

瞎搞

贪心的把目前的 (A_i) 加入到最小的 sum 中, 用 random_shuffle 瞎搞个几万次取最小值

class Solution {
public:
    
    int cal(vector<int>& jobs, int k){
        int sum[20] = {0};
        for(int v : jobs){
            int idx = 0,mx = 120000000;
            for(int i = 1;i <= k;i++){
                if(sum[i] < mx){
                    mx = sum[i];
                    idx = i;
                }
            }
            sum[idx] += v;
        }
        int ans = 0;
        for(int i = 1;i <= k;i++)ans = max(ans,sum[i]);
        return ans;
    }
    int minimumTimeRequired(vector<int>& jobs, int k) {
        int ans = 0x3f3f3f3f;
        int t = 50000;
        while(t--){
            random_shuffle(jobs.begin(),jobs.end());
            ans = min(ans, cal(jobs,k));
        }
        return ans;
    }
};
原文地址:https://www.cnblogs.com/sduwh/p/14291506.html