当前位置: 首页 > news >正文

利用位屏蔽和动态规划解决最小代价任务分配问题 Bitmasking Dynamic Programming

利用位屏蔽和动态规划解决问题 Bitmasking & Dynamic Programming

位屏蔽基础

上一篇简单介绍了位屏蔽的赋值操作,在解决问题之前,再介绍一下位屏蔽的去值操作以及检查操作。

去值操作:

b & !(1 << i)

例子:

取i = 1, (1 << i) = 00010

!(1 << i) = 11101 (每位取反)

b = 01010

b & !(1 << i) = 01010 & 11101 = 01000 (1位上的值已经去除)

检查操作:

b & (1 << i)

例子:

取i = 1, (1 << i) = 00010

b = 01010

b & (1 << i) = 01010 & 00010 = 00010 (结果不为0) 则检查位上有值,即子级中包含检查的值。

利用位屏蔽和动态规划解决问题

题目:

需要给N个人分配总共N个任务,每个人完成一个任务,并且给出一个 N x N 的矩阵,cost[i][j] 代表第i个人完成第j个任务的代价。现在我们要找出分配任务代价最小的方案。

暴力解法:
assign(N, cost)
	for i = 0 to N
		assignment[i] = i
	res = INFINITY
	for j= 0 to factorial(N)
		total_cost = 0
		for i = 0 to N
			total_cost = total_cost + cost[i][assignment[i]]
			res = min(res, total_cost)
			generate_next_greater_permutation(assignment)
		return res

暴力解法会遍历所有的排布,然后返回最小代价的值。其时间复杂度是O(N!)。

接下来用位屏蔽和动态规划的思路来尝试解一下题目:

定义函数 dp=(k, mask)
k表示前k个人(任务0~k-1)已经被分配了任务,mask表示当前的屏蔽字。
在分配第k个任务时,动态寻找dp的过程中,状态方程是:
dp(k + 1, mask | (1 << i)) = min(dp(k + 1, mask | (1 << i)), dp(k, mask) + cost[k][i])
可以注意到, 上述方程中的k是屏蔽字中‘1’的数量(屏蔽字中,被置为一的个数为已经分配掉的任务的个数,和k的意义相同,因此上述方程可以简化为:
dp(mask | (1 << i)) = min(dp(mask | (1 << i), dp(mask) + cost[x][i] (x为mask内1的个数)

因此,解法如下:

assign(N, cost)
	for i = 0 to power(2,N)
		dp[i] = INFINITY
	dp[0] = 0
	for mask = 0 to power(2, N)
		x = count_set_bits(mask)
		for j = 0 to N
			if jth bit is not set in i
				dp[mask | (1 << j)] = min(dp[mask | (1 << j)], dp[mask] + cost[x][j])
	return dp[power(2, N) - 1]

上述的算法的时间复杂度是O(2nn) 空间复杂度是O(2n)。

如果你对算法中有任何地方没办法自行理解的,请在评论区说出疑问,我会尽我所能帮你理解!

本文参考 via hackerearth: dynamic-programming/bit-masking

相关文章:

  • 算法:回溯法(backtracking)解决寻找给定字符串的所有排序(permutations)问题
  • 算法: 动态规划 寻找2D矩阵中到达某一坐标的最小代价路径
  • 算法:动态规划 寻找2D矩阵中到达某一坐标的可能路径总数
  • 算法:动态规划 寻找2D矩阵中到达某一坐标的可能路径总数进阶版(添加路障)
  • 算法: 动态规划,二维矩阵代价最值进阶版 两条行进路径,一次相交,求解最大代价
  • Programming Languages And Lambda calculi 1.1 定义集合
  • 算法: 动态规划 编辑距离 Edit Distance / Levenshtein Distance
  • 【Salesforce】【Apex】Trigger中不通过soql查询记录类型的开发名称
  • 【Programming Languages And Lambda calculi】 1.2 ~ 1.3 关系、赋值与关系
  • 【Programming Languages And Lambda calculi】 1.4 有向赋值
  • 【算法】 动态规划 基础题库 1-7 python实现
  • 【Programming Languages And Lambda calculi】 1.5 ~ 1.7 上下文规约 赋值函数 符号摘要
  • 【Programming Languages And Lambda calculi】第二章 结构归纳法 2.1 基础
  • 【Programming Languages And Lambda calculi】2.2 ~ 2.3 定义中的省略,证明树中的归纳
  • 【Programming Languages And Lambda calculi】2.4 ~ 2.5 多重结构,更多的定义与证明 第二章结束
  • EventListener原理
  • Java多线程(4):使用线程池执行定时任务
  • java概述
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • oschina
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 从零开始学习部署
  • 世界上最简单的无等待算法(getAndIncrement)
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 微信小程序填坑清单
  • 温故知新之javascript面向对象
  • 终端用户监控:真实用户监控还是模拟监控?
  • 最简单的无缝轮播
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (JS基础)String 类型
  • (第一天)包装对象、作用域、创建对象
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (转载)从 Java 代码到 Java 堆
  • .chm格式文件如何阅读
  • .CSS-hover 的解释
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...
  • @angular/cli项目构建--Dynamic.Form
  • @Autowired @Resource @Qualifier的区别
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • @transaction 提交事务_【读源码】剖析TCCTransaction事务提交实现细节
  • []T 还是 []*T, 这是一个问题
  • [C# 基础知识系列]专题十六:Linq介绍
  • [C++11 多线程同步] --- 条件变量的那些坑【条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)】
  • [C和指针].(美)Kenneth.A.Reek(ED2000.COM)pdf
  • [Delphi]一个功能完备的国密SM4类(TSM4)[20230329更新]
  • [EFI]Atermiter X99 Turbo D4 E5-2630v3电脑 Hackintosh 黑苹果efi引导文件
  • [HJ73 计算日期到天数转换]
  • [Linux] PXE批量装机