题目链接:Luogu P3547 [POI2013] CEN-Price List
题目描述:
给定一张边权均为
a
的无向图,现在将所有两点之间最短路为2a
的点之间增加一条长度为b
的无向边,问到给定点s
的单元最短路。
题解:
对于一个点
u
到s
的最短路只有三种情况:
- 经过的边边权均为
a
;- 经过的边边权均为
b
;- 经过的边边权
a
与b
均有。我们只需要求出上面三种情况的最短路取最小值即可。
对于情况一只需要进行一次
BFS
即可求出。对于情况二我们同样可以通过一次
BFS
求出:
- 我们首先建立两张与原图一样的图,我们将两张图的边权全部记作
1
这样只需在最后的时候乘以a
或者b
即可,将这两张图记为g
和newG
;- 对于本轮
BFS
的结点u
,标记其在g
中的相邻结点v
已访问;- 通过
g
遍历与u
相邻的结点v
,通过newG
遍历与v
相邻的结点w
;若w
已经被标记,则说明u
与w
之间的最短路为1
,此时两者之间不存在边长为b
的边,不能更新dis
;若w
并没有被标记,说明u
与w
之间的最短路距离为2
,此时存在边长为b
的边,所以进行更新dis[w] = dis[u] + 1
,并将w
入队,删除v
到w
的边;- 通过
g
遍历与u
相邻的结点v
,标记其为未访问。上述的过程需要删除
v
到w
的边,可以通过前向星实现(建立双向链表)。该算法与三元环计数类似,时间复杂度为 O ( ( n + m ) m ) O((n + m) \sqrt m) O((n+m)m )。能够删除的原因是:根据BFS
可以知道先遍历的点的dis
一定小于后遍历的点的距离,如果之前通过v
到w
的这条边更新过,后续通过这条边的距离一定会更大,因此不需要重复遍历。对于情况三我们可以发现最多只会经过一条边权为
a
的边。这是因为,如果我们经过了边权为b
的边,那么说明b<2a
否则不会更优,那么既然这样,每有两条边权为a
的边,则可以进行走一次边权为b
的边进行优化,最会只可能剩下一条或者零条边权为a
的边,如果将原图的边权改为1
求得一次的单元最短路的结果记为dis[u]
(u
与s
的最短路),则情况三为: ⌊ d i s [ u ] 2 ⌋ ∗ b + d i s [ u ] m o d 2 ∗ a \lfloor\frac {dis[u]} 2\rfloor * b + dis[u]\ mod\ 2 * a ⌊2dis[u]⌋∗b+dis[u] mod 2∗a。
代码:LuoguP3547