本篇并不适合初学者阅读。
SCC:
1.Tarjan缩点:x回溯前,dfn[x]==low[x]则缩点。
注意:
①sta,in[]标记。
②缩点之后连边可能有重边。
2.应用:
SCC应用范围还是很广的。
基本思路是:Tarjan+topo
DAG是个好东西。
各种判断连通性(传递关系),计数,以及dp转移
感觉90%以上的tarjan都是考SCC
衍生应用算法:
①2-SAT
②完备匹配的二分图必须边和可行边。
E-DCC
1.Tarjan找桥:x的一个子节点y,dfn[x]<low[y],边就是桥
注意:
①in_edge,对称建边号。不能从in_edge^1出发。但是可以走重边。
然后不经过桥dfs,找E-DCC
2.应用:
①最短路的必经边:建出最短路图,找桥即可。
②例题:poj3694
找出桥边,E-DCC缩点。
对于询问(x,y)x,y不在一个DCC,
找LCA,之后可以往上暴力找路径,干掉桥。
然鹅使用并查集更快。
O(M+N+Qlogn)
V-DCC
1.找割点:dfn[x]<=low[y]不用管重边什么的。
注意:
①搜索树根节点要有两次符合,才是割点。
其实对于割点x,dfn[x]<=low[y]的出点y,这些y一定在不同的DCC中。
缩点:
除了孤立点之外,每个DCC大小至少为2
每个割点属于多个DCC
用栈维护。
如果某个点满足dfn[x]<=low[y]
那么,不断弹出栈顶,直到y弹出。
把这些点和x都放进一个DCC中。(vector存)
可以发现一个x属于多个DCC
缩点的时候,
先把割点设置编号(cnt+1~cnt+tot)cnt是DCC个数
tot是割点个数
循环所有的DCC,循环所有的成员
如果找到割点,就让这个割点和这个DCC连边。
连出一个黑点白点相间的树(黑点可以认为是割点)
例题:
分类讨论即可
KNIGHTS - Knights of the Round Table
性质题,
建立反图。没有仇恨的人连边。
没有出现在任何一个简单奇环中的骑士滚蛋
V-DCC缩点
如果两个骑士DCC不同,一定不能同时出席。(否则在一个奇环中的话,那么两个DCC可以合并。矛盾)
如果一个DCC中有奇环,那么DCC中的所有骑士都可以被一个奇环包含。(可以构造)
综上,一个骑士被包含,因为不能和其他DCC合作,所以必须当且仅当自己的DCC中有奇环
Tarjan+二分图染色判断奇环
附赠福利:
欧拉回路:
void dfs(int x){
for(each son)
if(!vis[i]){
vis[i]=vis[i^1]=1;
dfs(e[i].to)
}
sta[++top]=x;
}
然后sta倒着输出即可。
至于每个点访问多次,可以弧优化减少枚举。