贪心算法介绍与示例

贪心算法每次都取当前这一步里收益最大的选择,并且之后不再反悔。我用活动安排和分数背包两个能保证最优的例子,把选择规则和 Python 实现写出来。

贪心算法把问题拆成一串选择。每一步只看当前信息,取这一步里收益最大的那个,选完就固定,后面的步骤在剩下的问题里继续。它能得到全局最优,需要两件事同时成立:当前这一步的最优选择可以安全地留在最终答案里,而且剩下的子问题仍然是同一类问题。

活动安排和分数背包满足这两点,所以下面的写法就是最优解。硬币凑整只在币值成套(例如 1、5、10、25)时,每次先拿最大面额才是最优;币值不成套时,这个规则会选错。

活动安排

有若干活动,每个活动占一段连续时间,同一时刻只能进行一个。目标是安排尽可能多的场次。

正确的贪心是:每次选结束最早、并且不和已选活动重叠的那场。结束越早,留给后面的空档越长。按结束时间排序后扫一遍即可。

def select_activities(activities):

chosen = \[\]

end = float("-inf")

for start, finish, name in sorted(activities, key=lambda item: item1):

if start >= end:

chosen.append(name)

end = finish

return chosen

activities = [

(1, 4, "A"),

(3, 5, "B"),

(0, 6, "C"),

(5, 7, "D"),

(3, 9, "E"),

(6, 10, "F"),

(8, 11, "G"),

(8, 12, "H"),

(2, 14, "I"),

(12, 16, "J"),

]

print(select_activities(activities))

输出是 ['A', 'D', 'G', 'J'],共 4 场。时间线是 1--4、5--7、8--11、12--16。C 虽然开始得早,但一直占到 6,会挤掉 A 和 D,所以按结束时间它不会被优先选中。

排序是 O(n log n),随后一次扫描是 O(n)。

分数背包

背包容量有限,每件物品可以只拿一部分,价值按拿走的比例计算。目标是总价值最大。

贪心规则是:优先拿单位重量价值最高的物品,当前这件还能装下多少就拿多少。因为可以拆分,把容量让给单价更高的物品始终更划算。

def fractional_knapsack(items, capacity):

taken = \[\]

total = 0.0

remain = capacity

ranked = sorted(items, key=lambda item: item0 / item1, reverse=True)

for value, weight, name in ranked:

if remain <= 0:

break

portion = min(1.0, remain / weight)

taken.append((name, round(portion, 2), round(value * portion, 2)))

total += value * portion

remain -= weight * portion

return taken, round(total, 2)

items = (60, 10, "a"), (100, 20, "b"), (120, 30, "c")

print(fractional_knapsack(items, 50))

三件物品的单价分别是 6、5、4。容量 50 时先整件拿走 a、b,剩下 20 的容量再拿走 c 的 2/3。结果是:

(('a', 1.0, 60.0), ('b', 1.0, 100.0), ('c', 0.67, 80.0), 240.0)

总价值 240。物品必须整件拿走时,这个「按单价装填」的规则不再保证最优,那种 0-1 背包要用动态规划。

怎么判断能不能用贪心

写之前先回答两个问题:

  1. 把当前这一步的选择固定下来以后,剩下的最优解接上去,整体仍然最优吗?
  2. 每一步的比较标准是否只依赖当前状态,不需要回头修改?

两个答案都成立,就按这个标准排序或扫描。活动安排的标准是结束时间,分数背包的标准是单位价值。证明不了第 1 点时,这一步的局部最优可能把后面的更好方案堵死,这时改用动态规划或搜索。

相关推荐
晚风叙码17 小时前
Linux 进程概念(下):程序地址空间与虚拟内存
linux·服务器·算法
silvamux_18 小时前
微头条爆款体平台适配实测:把交付要求变成可计算的指标
java·线性代数·算法·决策树·矩阵
重生之小比特18 小时前
【算法拾光】前缀和|连续的子数组和 + 和相同的二元子数组
算法·leetcode·哈希算法
一去不复返的通信er18 小时前
力扣15:盛最多水的容器
算法·leetcode
Navigator_Z18 小时前
LeetCode //C - 1309. Decrypt String from Alphabet to Integer Mapping
c语言·算法·leetcode
潇湘秦18 小时前
SQL Server 2016+ 整数类型元数据扩宽(秒级变更)完整说明
数据库·算法
SatanII19 小时前
Kubernetes 认证与授权详解:守护集群API访问安全
安全·贪心算法·kubernetes
Figo_Cheung20 小时前
Figo基于结构空间算法假设(SSAH)的生成式大模型优化范式与工程实现边界研究——提出适应AGI架构演化的自适应拓扑感知表征机制
算法·架构·agi
旖旎夜光20 小时前
LCR 170:交易逆序对的总数(归并排序) —— 题解
c++·学习·算法·leetcode·排序算法
微尘hjx1 天前
【ByteTrack 04】多轨迹算法ByteTrack改进点
算法·yolo·目标检测·目标跟踪·bytetrack·ultralytics·车跟踪