贪心

普通贪心

例题

P6093 [JSOI2015] 套娃

考虑将这 \(n\) 个套娃全部空置,我们的答案为 \(\sum_{i=1}^nin_i\times b_i\)。在当前情况下,如果我们再将一个套娃放进另一个套娃(不妨设这两个套娃为 \(i\)\(j\)),不满意度就减少了 \(out_i\times b_j\),又因为 \(in,out,b\) 是不会变的,同时本题也没有后效性,因为 \(out\) 大的套娃不影响其它套娃,可以考虑贪心(当然你也可以从最优化问题开始想,无非就是贪心或者DP,这题显然贪心可做一点)。

那么我们按照 \(b_i\) 为关键字对 \(n\) 个套娃从大到小排序,按照顺序依次将 \(out\) 大的但又不超过当前 \(b_i\)\(in_i\) 值的那个套娃套进去

考虑证明:

仍然设这两个套娃为 \(i\)\(j\)。如果 \(b_i>b_j,out_p>out_q\)\(in_i>in_p,in_i>in_q,in_j>in_p,in_j>in_q\) 的条件下,两种方案权值为 \(b_i\times out_p+b_j\times out_q\)\(b_i\times out_q+b_j\times out_p\),两式一相减得:\(b_i\times(out_p-out_q)+b_j\times (out_q-out_p)=(b_i-b_j)\times(out_p-out_q)>0\),所以这样的贪心策略是对的。

直接模拟贪心过程即可,时间复杂度:\(\mathcal O(n \log n)\)

P1269 信号放大器

典。

6307 -- 【10.06模拟】竞选

\(2^i\) 这种权值相当于你选择了 \(1\sim i-1\) 的数都不及 \(i\) 这一个数,所以考虑贪心,能不选后面的就不选后面的就行了。

树上贪心

例题

6304 -- 【10.05模拟】签到题

定顺序,肯定是树上组合优化问题,考虑 dp 和贪心。
考虑两个子树 \(x\)\(y\),先 \(x\)\(y\),先 \(y\)\(x\) 的贡献分别是:

\[2\times A_{x_1}+3\times A_{x_2}+\cdots+(sz_x+1)\times A_{x_{sz_x}}+(sz_x+2)\times A_{y_1}+(sz_x+3)\times A_{y_2}+\cdots+(sz_x+sz_y+1)\times A_{y_{sz_x+sz_y+1}} \]

\[2\times A_{y_1}+3\times A_{y_2}+\cdots+(sz_y+1)\times A_{y_{sz_y}}+(sz_y+2)\times A_{x_1}+(sz_y+3)\times A_{x_2}+\cdots+(sz_x+sz_y+1)\times A_{x_{sz_x+sz_y+1}} \]

两者相减得:

\[(A_{y_1}+A_{y_2}+\cdots+A_{sz_y})\times sz_x-(A_{x_1}+A_{x_2}+\cdots +A_{sz_{x}})\times sz_y\ge 0 \]

化简得:

\[\frac{sz_x}{A_{x_1}+A_{x_2}+\cdots+A_{x_{sz_x}}}\ge \frac{sz_y}{A_{y_1}+A_{y_2}+\cdots+A_{y_{sz_y}}} \]

时间复杂度:\(\mathcal O(n \log n)\)

7701 -- 【10.05测试】摧毁图状树

树上组合优化问题。

考虑贪心,发现 \(k\) 给得很大没有用,当 \(k\) 超过树高时答案就是树上叶子数量。

考虑一个贪心策略:我们维护一个堆,每次从堆中选取深度最大的一个未被覆盖的叶节点 \(u\),从 \(u\) 往上走 \(k\) 个节点,并将这 \(k\) 个节点都打上标记;然后再往上走一个节点,将其加入堆中。

考虑怎么维护这个过程,即我们要快速实现树链覆盖,单点查询是否被覆盖。

我们用树剖+线段树维护做到 \(\mathcal O(\log^2 n)\),但是由于题目中给出的是祖先-后代链,我们可以用 dfn 序+线段树来维护。就看一下 \(u\) 管辖的 dfn 区间中被染色的点中深度最小的那个点就行了。这样每次操作的时间复杂度就是 \(\mathcal O(\log n)\)

大多数情况下我们都覆盖了 \(k\) 个节点,因此操作一次的复杂度大概是 \(O(\frac{n}{k}\log n)\)

注意到 \(\sum \frac{n}{k}=\mathcal O(n \ln n)\),因此总复杂度就是 \(\mathcal O(n \log^2 n)\)

两个有效的优化:

  • 我们记录一下从叶节点开始覆盖一次之后应该覆盖的那些节点,第一次直接从这些节点开始往上走。这是因为只要 \(k\) 稍微大一点,那么第一次覆盖中叶节点的个数甚至可能会比后面的所有节点的总数加起来还要多。
  • \(k\) 超过了树高时,答案就是叶子结点的个数。直接输出即可。

AT_joisc2019_k 合併 (Mergers)

可以发现是把原树进行缩点后得到的树进行一些连边操作,使得树变为边双。

那么我们连边肯定要连叶子节点,否则无法满足边双要求,那么我们贪心地在叶子节点中两两连边,形成一个环,操作次数就是 \(\frac{叶子个数+1}{2}\)

图上贪心

例题

P7831 [CCO 2021] Travelling Merchant

我们用 $ ans_i $ 表示从城市 $ i $ 出发可以一直走下去的最小花费,所有 $ ans_i $ 初始赋值为 $ inf $,方便更新最小值,最后输出的时候判断一下如果为 $ inf $ 就输出 $ -1 $。

首先,对于出度为 $ 0 $ 的城市,我们可以直接将其删去,因为无论有多少钱都不可能一直走下去,其答案即为 $ -1 $。

那么,剩下的点都有出边,所以剩下的点一定有答案。

换一种思路,当有多少钱时,从城市 $ i $ 出发一定能一直走下去呢?当我们的钱数为当前最大的 $ r_i $ 时,可以一直走下去,因为当前的 $ r_i $ 是全场最大的,且 $ p_i $ 均不小于 $ 0 $,所以我们就可以一直走,不可能存在不能通行的道路。

可以采用一种类似于 拓扑排序 的算法,结合 贪心 思想。

  1. 把所有所有边按 $ r_i $ 排个序,每次取出 $ r $ 最大的那条边 $ edge_i $,设这条边起点为 $ u $,更新 $ u $ 的答案 $ ans_u = \min(ans_u,r_i) $。

  2. 如果这个点还有其它出边,那么我们就先记下这个答案,并删掉这条边。

  3. 如果这个点没有其它出边了,那么这个点答案就是确定的,将这个点入队,删掉这个点,这时可能会出现新的没有出度的点,它们的答案也确定了。

  4. 每一轮入队的点,在处理下一条边之前先处理,取出这个点的每一条进入的边 $ edge_i $,设其起点为 $ u $,终点为 $ v $,更新 $ u $ 的答案 $ ans_u=\min(ans_u,\max(r_i,ans_v-p_i)) $。 删去这条边,注意,在这过程中可能还会出现新的没有入度的点,也要记得进队。

  5. 重复如此,直到没有点。

反悔贪心

例题

P2209 [USACO13OPEN] Fuel Economy S

典。

CF436E Cardboard Box

考虑贪心。

最终状态每个数有三种状态:

  • 不选。
  • 选一个。
  • 选两个。

考虑怎么用贪心去刻画,由于 \(a_i\le b_i\),我们可以这么考虑,如果最后要选两个的话,我们先选出一个,最后再选出一个就行了。

…………………………………………………………

很可惜,我的思路是错误的。

如果 \(a_i\) 都很大,\(b_i-a_i\) 都很小这样显然是亏的。

考虑怎么弥补这种情况,我们使用反悔贪心,再加入两种情况:

  1. 选择一个已经选了一颗星的位置 \(i\),再选一个没有选星星的位置 \(j\),将原来\(i\)位置上选的那颗星星反悔不选,然后在位置 \(j\) 上选上两颗星,代价 \(b_j-a_i\)
  2. 选择一个已经选了两颗星的位置 \(i\),再选一个没有选星星的位置 \(j\),将原来\(i\)位置上的第二颗星星反悔不选,再在 \(j\) 位置上选两颗星星,代价 \(b_j-(b_i-a_i)\)

用堆每次从四种情况中选一种代价最小的拓展即可。

复杂度 \(\mathcal O(n\log n)\)

posted @ 2025-03-11 14:21  _apologize  阅读(21)  评论(2)    收藏  举报