状态压缩动态规划

leetcode 状态压缩动态规划

题目描述:

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

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


分析:

1 状态压缩:

jobs[a1,a2,...,an] 假设长度为n,那么从jobs中取出元素的情况有2n 种(每个ai取或者不取),每种状态都可以可以用一个n位的二进制数i表示 i[0, 2n1],

准确说i表示的是一个集合,该集合包含jobs中元素若干,比如对于jobs = [3,2,3],使用3(二进制就是011)表示选取了3,2两个元素。使用7(二进制111)表示选取了3,2,3元素;使用5(二进制101)表示选取了3,3两个元素。

2 动态规划

tot[i] 表示的是集合i中所含工作时间的总和,那么设i中某个元素在jobs中的下标为ji(1<<j) 表示从集合i中去掉了元素j,则可以得到

tot[i]=tot[i(1<<j)]+jobs[j]

使用dp[j][i]表示:前j个工人完成工作子集i所用的最大时间的最小值

状态转移方程为:dp[j][i]=minsi(max(dp[j1][is],tot[s]))

dp[j1][is]表示前j1个工人,完成工作子集is所用的最大时间的最小值,tot[s]表示的就是第j个工人完成工作子集s所用的时间

AC代码:

class Solution {
public:
    int minimumTimeRequired(vector<int>& jobs, int k) {
		int n = jobs.size();
		vector<int> tot(1<<n, 0); //创建一个2^n大小的tot数组,每个元素表示一个集合 
									// tot[i] 表示集合i的总工作时间
		// 集合0表示所有工作都不选,这种不用考虑 
		for(int i = 1; i < (1<<n); ++i) {
			for (int j = 0; j < n; ++j) {
				
				if((i & (1<<j)) == 0) continue; // 如果集合i中没有j这个元素 
				
				int rest = i - (1<<j);  // rest相当于把i的第j位清零
                
				tot[i] = tot[rest] + jobs[j]; //把jobs[j]的时间加入到集合中 
				break;//  
			}
		} 
		
		// 
		vector<vector<int>> dp(k, vector<int>(1<<n, -1));
		//初始化
		for (int i = 0; i < (1<<n); ++i) {
			dp[0][i] = tot[i]; //只有一个人做集合i,那么就是所有工作 
		}
		for (int i = 0; i < k; i++) {
            dp[i][0] = 0;  //集合0中有0个工作,
        }

		for(int j = 1; j < k; ++j) {
			for(int i = 1; i < (1<<n); ++i) {
				int min_val = INT_MAX;
				for(int s = i; s; s = (s-1) & i) {
                    int left = i - s;
					int val = max(dp[j-1][left], tot[s]);
					min_val = min(min_val, val);
				}
				dp[j][i] = min_val;
			}
		} 
        return dp[k-1][(1<<n)-1];
    }
};

参考题解:

https://leetcode-cn.com/problems/find-minimum-time-to-finish-all-jobs/solution/zhuang-ya-dp-jing-dian-tao-lu-xin-shou-j-3w7r/

posted @   VanHope  阅读(101)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示