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

思路:这种题我思考了三分钟想不出好的办法,直接看官方解答,并试图看懂了一种解题,即二分查找+回溯+剪枝
先考虑工作量顺序的分配,正如解答所说要先分配工作量大的工作,因为越到后面工作量越大越难分配(但其实从小到大分配也是一样能够解题的)
接下来考虑二分查找,这一题的思路其实是自己选择出答案再进行判断,利用二分查找能够更快的得到最短时间,这里需要考虑二分查找的上下限,如果只有一个工人,则所有工作都由他一人完成,所以此题的右边界是工作量之和;如果工作数和工人一样多,那么最短的时间就是工作量最大的那一个,这就是左边界。
回溯:就是对每一份工作,对每一个工人进行判断,如果在我们设定的最大量内,就可以考虑下一个工作,若超出界限,就要循环到下一个工人,如果全部不满足说明此限制不合理。关于剪枝,官方解答的一种剪枝没有理解,我只理解了对于第i个工人来说如果没有分配到工作,那么就不能对i+1个工人分配工作,说明当前设定的最短时间不合理,因此直接break循环返回false
对于满足返回true的情况来说,说明需要的最短时间将不大于当前设定的时间,所以右边界变为mid(即(left+right)/2),如果返回的false,说明需要的最短时间一定大于当前设定的时间,因此左边界left就要等于mid+1.

class Solution {
    bool Judy(vector<int>& jobs,vector<int>& worker,int sit,int limit)
    {
        //当工作都分配完了,就说明此方案可行
        if(sit>=jobs.size()) return true;
        //轮流遍历工人获取工作量
        for(int i=0;i<worker.size();++i)
        {
            //先加上当前工作的工作量
            worker[i]+=jobs[sit];
            //如果不大于限制
            if(worker[i]<=limit)
               //需要讨论下一个工作分配情况
               if(Judy(jobs,worker,sit+1,limit))
                 return true;
            //不满足的话就需要减去加上的工作量,回溯
            worker[i]-=jobs[sit];
            //这里剪枝
            //如果i工人没有分配到工作,那么i+1工人一定也不能分配工作
            if(worker[i]==0) break;
        }
        return false;
    }
    bool JudyMid(vector<int>& jobs,int& limit,int& k)
    {
        //worker[i]为第i+1个工人需要完成的工作量
        vector<int> worker(k);
        return Judy(jobs,worker,0,limit);
    }
public:
    int minimumTimeRequired(vector<int>& jobs, int k) {
        //先要排序,至于从小到大还是从大到小都能够求出答案
        //从大到小排序求解会提高解题效率
        sort(jobs.begin(),jobs.end(),greater<int>());
        //左边界为工作量最大的那一个
        int left=jobs[0];
        //右边界为工作量总和
        int right=accumulate(jobs.begin(),jobs.end(),0);
        //二分查找
        while(left<right)
        {
            //mid为设定的最小时间
            int mid=(left+right)/2;
            //当前时间符合说明最终解不大于mid,改变右边界
            if(JudyMid(jobs,mid,k))  right=mid;
            //否则最终解大于mid改变左边界
            else left=mid+1;
        }
        return right;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值