论考试前一直写WA,考试的时候碰到原题重新写代码就 A 了是什么玩意……
# 题面
> 洛谷 P5049
点击展开/折叠题面
小Y了解到,X国的 $n$ 个城市之间有 $m$ 条双向道路。每条双向道路连接两个城市。 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路。并且, 从任意一个城市出发,通过这些道路都可以到达任意一个其他城市。小 Y 只能通过这些 道路从一个城市前往另一个城市。
小 Y 的旅行方案是这样的:任意选定一个城市作为起点,然后从起点开始,每次可 以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市。当小 Y 回到起点时,她可以选择结束这次旅行或 继续旅行。需要注意的是,小 Y 要求在旅行方案中,每个城市都被访问到。
为了让自己的旅行更有意义,小 Y 决定在每到达一个新的城市(包括起点)时,将它的编号记录下来。她知道这样会形成一个长度为 $n$ 的序列。她希望这个序列的字典序最小。
# 解析
原题 $O(n^2)$ 可过,就直接枚举环上的边删掉,做 n 次树的简单贪心。现在要砍掉一个 $O(n)$ 的复杂度,于是不能枚举删掉哪条边。
原来的做法,删掉一条边,相当于在沿着环走到那条边的时候不继续走,而是调头“返回”。
为了方便表示,我们找到图上几个特殊的点:
从点 1 第一次进入环的点是 st
,沿着环走到的下一个点是 ca
,一直走到 cc
然后“返回”,又从 cb
沿着环走,一直走到 cd
结束。
st
是确定的,那么 ca
一定是 st
在环上相邻的两个点中较小的,另一个是 cb
。于是我们需要判断的是 cc
在哪里(cd
就是 cc
另一边的点),即在哪个点返回。
我们发现 cc,cd
具有以下性质:
- 记从
cc
返回到环的上一个点,按照贪心策略下一个经过的点为mn
,则cd>mn
; cd
应该比cc
相邻的所有不在环上的点大(如果是比cd
小的cc
相邻的不在环上的点,则应该在cd
之前就已经考虑,如果还存在比cd
大的点,则返回时一定会先经过,比直接去cd
差)
根据这两点,我们在 DFS 时,假如当前点 u 在环上,而且考虑沿着环到下一个点 v,则可以通过下面的方法判断 u 是否是 cc
:
- v 是 u 要考虑的最后一个点(对应性质2)
- v 比
mn
大(对应性质1); - 当前还没有经过
cb
(即不是已经返回了的情况);
如何维护 mn
?如果我们从环上的 u 沿环走到 v,则更新 mn
为 u 的下一个要考虑的点(如果存在,不存在则不更新)。可以发现当我们从 st
到 ca
时,mn
至多是 cb
,一定存在。
# 源代码
1 | /*Lucky_Glass*/ |
THE END
Thanks for reading!
> Linked ファンサ-bilibili