【动态规划 子集状态压缩 回溯】1723. 完成所有工作的最短时间

本文涉及知识点

动态规划 子集状态压缩 回溯
动态规划汇总

回溯知识汇总

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

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

动态规划

n = jobs.length
vNeed[mask]记录 一个工人完成mask工作需要的时间。

动态规划的状态表示

dp[i][mask] 表示前i个工人完成了mask任务的最大工作时间。
用滚动向量 优化空间,pre[mask]表示dp[i][mask] dp[mask]表示dp[i+1][mask]。
空间复杂度: O(2n)

动态规划的转移方程

枚 举 c u r M a s k = 1 m a s k C o u n t − 1 枚 举 c u r S e l = c u r M a s k 的非空子集 d p [ c u r M a s k ] = m i n ( d p [ c u r M a s k ] , m a x ( p r e [ c u r M a s k − c u r S e l ] , v N e e d [ c u r S e l ] ) ) 枚举_{curMask=1}^{maskCount-1}枚举_{curSel=curMask的非空子集}\\ dp[curMask] = min(dp[curMask],max(pre[curMask-curSel],vNeed[curSel])) curMask=1maskCount1curSel=curMask的非空子集dp[curMask]=min(dp[curMask],max(pre[curMaskcurSel],vNeed[curSel]))

动态规划的填表顺序

依次处理各工人

动态规划的初始值

pre[0]=0,其它表示不存在的大值。

动态规划的返回值

pre.back

动态规划的代码

核心代码

class Solution {
public:
	int minimumTimeRequired(vector<int>& jobs, int k) {
		const int n = jobs.size();
		const int maskCount = 1 << n;
		vector<int> vNeed(maskCount);
		for (int i = 0; i < n; i++) {
			vNeed[1 << i] = jobs[i];
		}
		for (int mask = 1; mask < maskCount; mask++) {
			const int end = mask & (-mask);
			vNeed[mask] = vNeed[mask - end] + vNeed[end];
		}
		vector<int> pre(maskCount, m_iNotMay);
		pre[0] = 0;
		for (int i = 0; i < k; i++) {
			auto dp = pre;
			for (int curMask = 1; curMask < maskCount; curMask++) {
				for (int curSel = curMask; curSel; curSel = (curSel - 1) & curMask) {
					dp[curMask] = min(dp[curMask], max(pre[curMask - curSel] , vNeed[curSel]));
				}
			}
			pre.swap(dp);
		}
		return pre.back();
	}
	const int m_iNotMay = 1'000'000'000;
};

测试用例

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		assert(v1[i] == v2[i]);
	}
}

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

int main()
{
	vector<int> jobs;
	int k;
	{
		Solution slu;
		jobs = { 3, 2, 3 }, k = 3;
		auto res = slu.minimumTimeRequired(jobs, k);
		Assert(3, res);
	}
	{
		Solution slu;
		jobs = { 1,2,4,7,8 }, k = 2;
		auto res = slu.minimumTimeRequired(jobs, k);
		Assert(11, res);
	}
}

回溯

直接回溯超时,需要剪枝,过于复杂。本代码超时。

class Solution {
public:
	int minimumTimeRequired(vector<int>& jobs, int k) {
		const int n = jobs.size();
		sort(jobs.begin(), jobs.end(), greater<>());
		vector<int> vWork(k);
		int iRet = 1'000'000'000;
		function<void(int,int, vector<int>)> BackTrack = [&](int leve,int iMax, vector<int> vWork) {
			if (iMax >= iRet) { return; }
			if (jobs.size() == leve) {
				iRet = min(iRet, iMax);
				return;
			}			
			sort(vWork.begin(), vWork.end());
			for (int i = 0; i < k; i++) {			
				vWork[i] += jobs[leve];
				BackTrack(leve + 1,max(iMax, vWork[i]),vWork);
				vWork[i] -= jobs[leve];
			}
		};
		BackTrack(0, 0,vWork);
		return iRet;
	}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻缺陷则喜何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值