贪心总结
贪心题一般没有什么技巧,多做题积累经验。
对于结论或策略,大胆猜想,小心求证,注意使用数据结构优化 / 结合其他算法。
Exchanging Arguments
全序关系(Total Order):
设集合 \(X\) 上的二元关系 \(\leq\) 满足以下三条公理,则称 \(\leq\) 为全序关系:
- 反对称性(Antisymmetry)
若 \(a \leq b\) 且 \(b \leq a\),则 \(a = b\)(即不存在两个不同元素互相“小于等于”)。 - 传递性(Transitivity)
若 \(a \leq b\) 且 \(b \leq c\),则 \(a \leq c\)(序关系可递推)。 - 完全性(Comparability / Totality)
对任意 \(a, b \in X\),必有 \(a \leq b\) 或 \(b \leq a\)(任意两元素可比较大小)。
满足全序关系的集合称为全序集(Totally Ordered Set),也称为线性序集或链(Chain)。
- 有一全序集 \(S\) 上的全序 \(<\),给定 \(S\) 中元素组成的序列 \(p\)。
- 定义了序列的价值 \(f(p)\),若 \(q\) 是 \(p\) 交换了一对 \(p_{i+1}<p_i\) 的 \(p_i,p_{i+1}\) 之后的排列,有 \(f(q)\le f(p)\)。
- 如何排列 \(p\) 以最小化 \(f(p)\)?
结论:排序 \(p\) 使得 \(p_i<p_{i+1}\),此时 \(f(p)\) 最小。
证明:如果没有完成排序,一定存在 \(p_i>p_{i+1}\),交换可得更优解。因此没有排序好的序列全部不是最优解,可能是最优解的只剩下排序好的序列,这就是最优解。
如果是偏序,这个结论就不一定正确了。
Fight Against Monsters
先用二分求出每个怪需要打的次数。
问题转化为

一个排列的答案是
考虑邻项交换 \(i,i+1\),答案的变化就为
如果交换更优,应满足
按照属性升序排序即可。
打怪兽2

对于 \(b_i \ge a_i\) 的肯定先打,按照 \(a_i\) 排序。
对于 \(b_i < a_i\) 的,考虑邻项交换。
设现在还剩血量 \(t\),面对怪兽 \((a_i,b_i),(a_{i+1},b_{i+1})\),若不交换更优,应满足
由 \(b_i<a_i\)
只能有
按照 \(b\) 降序排序即可。
Hall 定理
AT_arc147_e [ARC147E] Examination
学了二分图的 Hall 定理,写一篇题解记录一下。
Hall 定理
一个二分图存在 完备匹配 ,当且仅当 \(V_1\) 中任意 \(k\) 个顶点至少连接 \(V_2\) 中 \(k\) 个顶点。
这里就不加证明,读者可自行查阅资料。
给定两个数组 \(A,B\),可以选择 \(A\) 的一些位置任意重排,使得对于任意的 \(i\) 都有 \(A_i \ge B_i\)。
现将 \(A,B\) 排序,本题可以转化为一个二分图的问题,如果有 \(A_j \ge B_i\),则 \(i,j\) 连边。
先把无解的情况判了,如果存在 \(A_i < B_i\) 则无解。证明是容易的,如果存在这个 \(i\),那么 \(i\) 以及其后面一共 \(n-i+1\) 个点在二分图中对应的右部点最多只有 \(n-i\) 个点,根据 Hall 定理,此时二分图不存在完备匹配,故无解。
接下来考虑最小化被选中重排的集合 \(S\),那么 \(A_i < B_i\) 的一定要包含在集合中,同时 \(S\) 以及对应的 \(N(S)\) 也应具有完备匹配。
于是我们先将 \(A_i < B_i\) 的提取出来做个排序,如果无法满足条件,则说明一定要从已经合法的一对提取出来,不难发现,我们想要的是 \(j\) 满足 \(B_j \le A_i\) 且 \(A_j\) 最大。感性理解这样正确的原因,我们第一个约束满足了选出来的集合 \(S\) 一定有 \(A_i\ge B_i\),第二个约束能使得后面的决策能更容易地被满足,缩减 \(S\) 的规模。
具体地,我们使用两个小根堆维护二分图的左部点集合 \(V_1\),右部点集合 \(V_2\)。依次检索 \(V_1,V_2\) 所有对应元素,如果合法则跳过,否则选取未被选取的点中 \(B_j \le A_i\) 且 \(A_j\) 最大的,这个可以依次加入并用大根堆维护。
时间复杂度,排序和堆都是 \(\Theta(n \log n)\) 的。
反悔贪心 & 模拟费用流
思路是确定一个全序关系,我们肯定会在排好序的序列中选一段子序列按顺序做。至于怎么选就是反悔操作。
P2949 [USACO09OPEN] Work Scheduling G
题目大意:给个任务有一个截止时间,每个时间安排一个任务,求最大利润。
使用 Exchanging arguments 确定贪心顺序。
假设最优解是选 \(T = \{(d_1,p_1),(d_2,p_2),\dots,(d_n,p_n)\}\)。
交换相邻两项 \((d_i,p_i),(d_{i+1},p_{i+1})\)。
那么 \(T\) 更优说明:
- \(d_i = d_{i+1}\),此时 \(p_i>p_{i+1}\)。
- \(d_i \not = d_{i+1}\),设之前用时为 \(t\),此时 \(t\le d_i,t+1\le d_{i+1},t \le d_{i+1},t+1>d_i\),得到 \(d_{i} < d_{i+1}\)。
容易证明上面是一个全序关系。
然后就是反悔部分。
使用一个堆维护决策,如果当前的能做就做,否则如果之前的任务有收益更低的就用当前任务替换。
P4053 [JSOI2007] 建筑抢修
题目大意:每个任务有所需时间和截止时间,求最多能安排多少任务。
朴素贪心:按照截止时间排序,扫一遍判断是否能做。
此时就会有无法做的任务,我们会直接舍弃,给前面一个任务很多的时间,贪心错误,考虑反悔。
用一个大根堆维护决策集合,具体维护其时间。如果当前时间能够做这个任务,就直接做。否则,一定有一个任务是不能做的,只能尽可能地压缩当前时间,以保证后面能安排更多的任务。于是考虑从大根堆中取出耗费时间最多的决策去除,消去其贡献。
注意一定要先贪心再反悔。
贪心证明:
假设我们确定了要选 \(S\) 中的所有任务,通过邻项交换推导策略。
记之前已经用的时间为 \(t\),即 \(\sum_{k=1}^{i-1} a_k = t\)
对于相邻的 \(i,j\),交换前更优,即满足交换后就没法完成第二个任务了,有
故是按照截止时间排序。
然后就可以通过转化,将这个问题建模为其他问题:
P11457 [USACO24DEC] Job Completion G
邻项交换容易证明按照截止时间排序。
证明跟上一题是一样的。
使用堆维护决策,如果能加就加入,否则要在保证答案最优的条件下取最小的时间。
P2107 小 Z 的 AK 计划
直接按顺序反悔贪心,走到 \(i\) 机房时,能做就做,用堆维护所有决策,当不能 AK 时,就替换一个时间最大的。
Zabuton
将每个人抽象成任务,拥有任务所需时间和截止时间,那么添加的砖就是任务所需时间。
CF865D Buy Low Sell High
一种直观的想法是如果能赚钱就直接卖掉,显然是错误的。
考虑设计一种反悔自动机来修正贪心决策。
使用一个堆维护可以买的股票,显然当天的最优决策是 \(x_i - Q.top()\),做完决策后,我们不妨将 \(x_i\) 再次压入优先队列。
这样的好处是,考虑股票 \(i\) 的最佳配对 \(j\),但是在 \(k\) 时 \(i,k\) 配对了(\(x_i<x_k<x_j\)),此时在考虑到 \(k\) 时我们一定会有一个决策 \(j,k\) 配对,全局的收益是 \(x_k-x_i\),保证了正确性!

浙公网安备 33010602011771号