Leetcode1723. 完成所有工作的最短时间 dfs剪枝优化

题目描述

给你一个整数数组 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 。

解题思路

记录自题解
可以选择枚举工人,给每个工人分配工作,搜素的时候同时维护最大的工作时间,记录答案时维护最大工作时间的最小化。

剪枝:如果当前搜素分支的最大工作时间已经大于答案,那么就可以提前return

code(TLE)

class Solution {
public:
    int n, k, ans = INT_MAX;
    vector<int> jobs;
    vector<int> sum;
    int minimumTimeRequired(vector<int>& _jobs, int _k) {
        jobs = _jobs;
        k = _k;
        n = jobs.size();
        sum = vector<int>(n, 0);
        dfs(0, 0);
        return ans;
    }

    void dfs(int u, int maxt) {
        if (maxt >= ans) return;
        if (u == n) {
            ans = maxt;
            return;
        }

        for (int i = 0; i < k; i ++ ) {
            sum[i] += jobs[u];
            dfs(u + 1, max(maxt, sum[i]));
            sum[i] -= jobs[u];
        }
    }
};
剪枝优化

然而上面的剪枝还不够彻底。**题目其实是让我们将n个数分为k份,并且尽可能让k分平均,这样[最大工作时间]才是最小的。**而我们上述的dfs时将每个任务依次分给每个工人,相当于二叉树的一棵高度为nk阶树。所以其实我们第一次更新的ans其实是最差的答案在这里插入图片描述
朴素版的dfs是弱化了剪枝效果

想要最大化剪枝效果,并且让k平均的话,我们应当调整我们对于[递归树]的搜索方向:将任务优先分配给[空闲工人]
在这里插入图片描述

class Solution {
public:
    int n, k, ans = INT_MAX;
    vector<int> jobs;
    vector<int> sum;
    int minimumTimeRequired(vector<int>& _jobs, int _k) {
        jobs = _jobs;
        k = _k;
        n = jobs.size();
        sum = vector<int>(n, 0);
        dfs(0, 0, 0);
        return ans;
    }

    void dfs(int u, int used, int maxt) {
        if (maxt >= ans) return;
        if (u == n) {
            ans = maxt;
            return;
        }

        if (used < k) {
            sum[used] = jobs[u];
            dfs(u + 1, used + 1, max(maxt, sum[used]));
            sum[used] = 0;
        }

        for (int i = 0; i < used; i ++ ) {
            sum[i] += jobs[u];
            dfs(u + 1, used, max(maxt, sum[i]));
            sum[i] -= jobs[u];
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值