题目链接:
http://acm.bnu.edu.cn/v3/problem_show.php?pid=23628
这道题是一道图论的综合题。题意较简单,如果对图论部分算法较为熟悉,那么很快便能找到清晰的解题思路。而且这道题中涉及了多种算法,对新手来说这是个很好的训练自己,提升自己的题目。
这是一个有向图A(可能有环)的最小路径覆盖问题。首先,利用【tarjan算法】缩点,得到一个DAG图B,然后用算一次图B的传递闭包,因为下一步利用二分图匹配去算最小路径覆盖的时候,所需要的边不仅仅是图B原来存在的边,而是B图的传递闭包中所有的边,具体原因看这里:
http://www.cnblogs.com/ka200812/archive/2011/07/31/2122641.html
算传递闭包的方法有很多,比如:
1 Floyd-Warshall算法 http://www.nocow.cn/index.php/Floyd-Warshall%E7%AE%97%E6%B3%95#.E6.94.B9.E8.BF.9B.E5.92.8C.E4.BC.98.E5.8C.96
2 对每个点做一次 dfs / bfs(优化)
3 对每个点做一次 spfa(优化)
因为在这道题中,顶点数为10^3,边数为10^5,时间限制是4s,所以用Floyd-Warshall算法会超时,从而只能选择用2,3两种方法,而且必须是利用边邻接表优化过的算法,否则仍然会超时。
剩下的就是利用二分图匹配来算最小路径覆盖,我使用的是【Hopcroft-Carp 算法】。
这道题我前前后后做了一个多月,主要是想尝试找出一个更简单的求最小路径覆盖的方法,但是后来发现自己想到的方法中均出现了不好处理的错误,于是最终还是选择了使用二分图匹配法,之后又发现自己使用【Floyd-Warshall算法】算传递闭包时O(n^3)的复杂度会使得程序超时,转念想到稀疏图中【spfa算法】有更好表现(复杂度为O(ke),k近似为2),最终利用更快的spfa求得传递闭包。此题终结。
![](http://img.e-com-net.com/image/info8/8945bff43846445e96208e516bad6ad1.jpg)
最后是3488ms时间AC了,但是和其他人的代码比起来,我自己的代码明显还有更多的优化空间:
![](http://img.e-com-net.com/image/info8/e7dec92812964a5ba70f18abfc257772.jpg)
![](http://img.e-com-net.com/image/info8/25c0f6d078834e9d92c059a598d29bc8.jpg)
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include