标签:技术分享 自己 地方 cut span none 存在 sed printf
tarjan算法可以在图上求解LCA,强连通分量,双联通分量(点双,边双),割点,割边,等各种问题。
这里简单整理一下tarjan算法的几个应用。
http://www.cnblogs.com/mjtcn/p/6852646.html
有向图的
强联通:在一个有向图G里,设两个点 a b 发现,由a有一条路可以走到b,由b又有一条路可以走到a,我们就叫这两个顶点(a,b)强连通。
强连通图: 如果 在一个有向图G中,每两个点都强连通,我们就叫这个图,强连通图。
强连通分量:在一个有向图G中,有一个子图,这个子图每2个点都满足强连通,我们就叫这个子图叫做 强连通分量 [分量:把一个向量分解成几个方向的向量的和,那些方向上的向量就叫做该向量(未分解前的向量)的分量]
http://www.cnblogs.com/mjtcn/p/7599217.html
无向图的
边双联通图:如果在一个无向图中,任意两点至少存在两条边不重复路径,则称该图为边双连通的。
边双联通分量:边双连通的极大子图称为边双连通分量。
原理和强联通分量的求法差不多。
1 void tarjan(int u,int fa) { 2 dfn[u] = low[u] = ++tn; 3 st[++top] = u; 4 vis[u] = true; 5 for (int i=head[u]; i; i=e[i].nxt) { 6 int v = e[i].to; 7 if (!dfn[v]) { 8 tarjan(v); 9 low[u] = min(low[u],low[v]); 10 } 11 else if (vis[v] && v!=fa) 12 low[u] = min(low[u],dfn[v]); 13 } 14 if (dfn[u] == low[u]) { 15 ++cnt; 16 do { 17 vis[st[top]] = false; 18 bel[st[top]] = cnt; 19 top--; 20 } while (st[top+1] != u); 21 } 22 }
简单点可以这样写,low数组可以有bel数组的作用
1 void tarjan(int u,int fa) { 2 dfn[u] = low[u] = ++tn; 3 for (int i=head[u]; i; i=e[i].nxt) { 4 int v = e[i].to; 5 if (!dfn[v]) { 6 tarjan(v,u); 7 low[u] = min(low[u],low[v]); 8 } 9 else if (dfn[v] < dfn[u] && v != fa) 10 low[u] = min(low[u],dfn[v]); 11 } 12 }
无向图的
图的割点
在一个无向连通图中,如果删除某个顶点后,连通分量数目增加,称这样的点为割点(或者称割顶)。
朴素的求法O(n(n+m)),尝试删除每个点,dfs判断是否联通。
tarjan算法复杂度O(n+m),线性!!!
割点的条件:
所以只要让low[v] >= dfn[u]即可。
1 void tarjan(int u,int fa) {
2 low[u] = dfn[u] = ++tn;
3 int cnt_son = 0;
4 for (int i=head[u]; i; i=e[i].nxt) {
5 int v = e[i].to;
6 cnt_son++;
7 if (!dfn[v]) {
8 tarjan(v,u);
9 low[u] = min(low[u],low[v]);
10 if (low[v] >= dfn[u])
11 iscut[u] = true;
12 }
13 else if (dfn[v] < dfn[u] && v != fa)
14 low[u] = min(low[u],dfn[v]);
15 }
16 if (fa==-1 && cnt_son==1) iscut[u] = false;
17 }
无向图
在一个无向连通图中,如果删除某条边后,图不再连通,这条边就是割边(桥)。
如果u的一个子节点v,它的所有子节点及其自己都不能连回u的祖先,这里包括也不能连向u,那么u-v,就是一个割边
代码只要改一个地方,low[v] > dfn[u]
1 void tarjan(int u,int fa) { 2 dfn[u] = low[u] = ++tn; 3 for (int i=head[u]; i; i=e[i].nxt) { 4 int v = e[i].to; 5 if (!dfn[v]) { 6 tarjan(v,u); 7 low[u] = min(low[u],low[v]); 8 if (low[v] > dfn[u]) { 9 printf("%d %d\n",u,v); 10 } 11 } 12 else if (dfn[v] < dfn[u] && v != fa) 13 low[u] = min(low[u],dfn[v]); 14 } 15 }
标签:技术分享 自己 地方 cut span none 存在 sed printf
原文地址:http://www.cnblogs.com/mjtcn/p/7895083.html