【LeetCode每日一题】1723. 完成所有工作的最短时间

【LeetCode每日一题】1723. 完成所有工作的最短时间

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

1.题目:

给你一个整数数组 jobs ,其中 jobs[i] 是完成第 i 项工作要花费的时间。
请你将这些工作分配给 k 位工人。所有工作都应该分配给工人,且每项工作只能分配给一位工人。工人的 工作时间 是完成分配给他们的所有工作花费时间的总和。请你设计一套最佳的工作分配方案,使工人的 最大工作时间 得以 最小化 。
返回分配方案中尽可能 最小 的 最大工作时间 。

2.示例①:

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

3.示例②:

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

4.题解:

直接写dfs,容易超时。

class Solution {
public:
    int ans;
    int minimumTimeRequired(vector<int>& jobs, int k) {
        ans = 0x3f3f3f3f;
        vector<int> worker(k);
        dfs(jobs, 0, worker, 0);
        return ans;
    }

    void dfs(vector<int>& jobs, int i, vector<int> worker, int cur) {
        if (i == jobs.size()) {
            ans = min(ans, cur);
            return;
        }
        for (int j = 0; j < worker.size(); j++) {
            if (worker[j] + jobs[i] >= ans) continue; 
            worker[j] += jobs[i];
            dfs(jobs, i + 1, worker, max(worker[j], cur));
            worker[j] -= jobs[i];
        }
    }
};

第一种剪枝:当前累计大于等于最终结果时,直接不予考虑。

第二种剪枝:k个工人在同一层如果值相同,那么直接可以跳过,

第三种剪枝:这道题要求最小,那么加上从小到大排序,便可以达到剪枝效果。

class Solution {
public:
    int ans;
    int minimumTimeRequired(vector<int>& jobs, int k) {
        ans = 0x3f3f3f3f;
        vector<int> worker(k);
        sort(jobs.begin(), jobs.end(), std::less<int>()); // 第三种
        dfs(jobs, 0, worker, 0);
        return ans;
    }

    void dfs(vector<int>& jobs, int i, vector<int> worker, int cur) {
        if (i == jobs.size()) {
            ans = min(ans, cur);
            return;
        }
        set<int> s;
        for (int j = 0; j < worker.size(); j++) {
            if (s.count(worker[j])) continue; // 第二种
            s.insert(worker[j]);
            if (worker[j] + jobs[i] >= ans) continue;  // 第一种
            worker[j] += jobs[i];
            dfs(jobs, i + 1, worker, max(worker[j], cur));
            worker[j] -= jobs[i];
        }
    }
};

在给k个工人分配工作时,容易造成某个人分配工作过多,其他人闲置情况,为了解决这种问题,我们可以采用轮询办法。

假设有三个人,if执行完成。第一轮:退出dfs(used+1)语句, sum[used] = 0语句回退空余的丙。进入for(i < used),对下一个任务在甲乙之间分配(注意此时used为2,区间为甲乙,和dfs(used+1)的参数不同)。然后进入dfs,这时再进if,给空余的丙分配任务。

第二轮,退出dfs,回退空余的乙丙,进入for(i < used),对下一个任务在甲之间分配。然后进入dfs,这时再进if,给空余的乙丙分配任务。再次进入回溯步骤。

class Solution {
public:
    int ans;
    int minimumTimeRequired(vector<int>& jobs, int k) {
        ans = 0x3f3f3f3f;
        vector<int> worker(k);
        // sort(jobs.begin(), jobs.end(), std::less<int>());
        dfs(jobs, 0, 0, worker, 0);
        return ans;
    }

    void dfs(vector<int>& jobs, int i, int used, vector<int> worker, int cur) {
        if (i == jobs.size()) {
            ans = min(ans, cur);
            return;
        }

        if (used < worker.size()) {
            worker[used] = jobs[i];
            dfs(jobs, i + 1, used + 1, worker, max(worker[used], cur));
            worker[used] = 0;
        }
        // set<int> s;
        for (int j = 0; j < used; j++) {
            // if (s.count(worker[j])) continue;
            // s.insert(worker[j]);
            if (worker[j] + jobs[i] >= ans) continue; 
            worker[j] += jobs[i];
            dfs(jobs, i + 1, used, worker, max(worker[j], cur));
            worker[j] -= jobs[i];
        }
    }
};

[2] 473. 火柴拼正方形

1.题目:

还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。

输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。

2.示例①:

输入: [1,1,2,2,2]
输出: true

解释: 能拼成一个边长为2的正方形,每边两根火柴。

3.示例②:

输入: [3,3,3,3,4]
输出: false

解释: 不能用所有火柴拼成一个正方形。

4.题解:

class Solution {
public:
    bool makesquare(vector<int>& matchsticks) {
        int ans = 0;
        for (auto x : matchsticks) {
            ans += x;
        }
        if (ans % 4 || !ans) return false;
        vector<int> vex(4);
        // 从大到小排序
        sort(matchsticks.begin(), matchsticks.end(), std::greater<int>());
        return dfs(matchsticks, 0, vex, ans / 4);
    }

    bool dfs(vector<int>& matchsticks, int i, vector<int> vex, int edge) {
        if (i == matchsticks.size()) {
            if (vex[0] == vex[1] && vex[1] == vex[2] && vex[2] == vex[3]) return true;
            return false;
        }
        for (int j = 0; j < 4; j++) {
            if (vex[j] + matchsticks[i] > edge || (j > 0 && vex[j] == vex[j-1])) continue; 
            // vex[i] == vex[i - 1]即上一个分支的值和当前分支的一样,
            // 上一个分支没有成功,说明这个分支也不会成功,直接跳过即可。
            vex[j] += matchsticks[i];
            bool res = dfs(matchsticks, i + 1, vex, edge);
            if (res) return true;            
            vex[j] -= matchsticks[i];
        }
        return false;
    }
};

同第一题,也可以加上解决闲置问题策略。

class Solution {
public:
    bool makesquare(vector<int>& matchsticks) {
        int ans = 0;
        for (auto x : matchsticks) {
            ans += x;
        }
        if (ans % 4 || !ans) return false;
        vector<int> vex(4);
        sort(matchsticks.begin(), matchsticks.end(), std::greater<int>());
        return dfs(matchsticks, 0, 0, vex, ans / 4);
    }

    bool dfs(vector<int>& matchsticks, int i, int used, vector<int> vex, int edge) {
        if (i == matchsticks.size()) {
            if (vex[0] == vex[1] && vex[1] == vex[2] && vex[2] == vex[3]) return true;
            return false;
        }
        if (used < 4) {
            vex[used] = matchsticks[i];
            bool res = dfs(matchsticks, i + 1, used + 1, vex, edge);
            if (res) return true;   
            vex[used] = 0;
        }
        for (int j = 0; j < used; j++) {
            if (vex[j] + matchsticks[i] > edge || (j > 0 && vex[j] == vex[j-1])) continue;
            vex[j] += matchsticks[i];
            bool res = dfs(matchsticks, i + 1, used, vex, edge);
            if (res) return true;            
            vex[j] -= matchsticks[i];
        }
        return false;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值