Tarjan算法详解
来源:互联网 发布:流畅的python pdf 编辑:程序博客网 时间:2024/06/05 18:14
Tarjan算法的用途
1.求桥和割点
2.求点和边的双连通分量
3.求强连通
Targan算法的流程
利用dfs来遍历图来构建一种数型的结构
Tarjan算法的两个核心数组
dfn:我们用dfn数组记录
low:我们用low[i]表示一个节点的子树中可以到达最小的dfn
(显然对于一个刚刚遍历到的点我们给他赋上一个新的dfn,low)
<1>对于第一种用途
Tarjan算法原理
我们从1开始遍历,发现6,5,4的low不小于dfn[3],故3为割点(即4,5,6都无法到达3以上的点)
我们发现对于边(2,5)low[5]大于dfn[2]即5的子树中的任何点无论如何都无法通过其他方式到2以上的点
于是我们得到了一个桥。
例题:给出一张连通的无向图G,求出至少加入多少条边才能使得图G是一个边双连通的。
即求边双连通分量把度为一的节点数x (x+1)/2即为答案
注意:求边双连通分量时low相同的即为同一组
const int M=10005;bool map[M][M],vis[M]; int low[M],dfn[M],cnt[M],num,n,m;void init(){ Mt(vis);Mt(map);Mt(low); Mt(dfn);Mt(cnt);num=0;}void dfs(int x,int f){ dfn[x]=low[x]=++num; for(int i=1;i<=n;i++){ if(i!=f&&map[x][i]) if(!dfn[i]){ dfs(i,x); Min(low[x],low[i]); }else Min(low[x],dfn[i]); }}int main(){ scanf("%d %d",&n,&m); while(m--){ int x,y; scanf("%d%d",&x,&y); map[x][y]=map[y][x]=1; }dfs(1,0); int ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(map[i][j]) if(low[i]!=low[j])//注意:求边双连通分量时low相同的即为同一组 cnt[low[j]]++; for(int i=1;i<=n;i++) if(cnt[i]==1)ans++; printf("%d",(ans+1)/2); return 0;}
例题:
给出一个无向图,你可以在一些点设置一些出口,使得删去任意一个点之后,其他所有的点都至少与一个出口连通,求在出口数量最小情况下的放置出口的方案。
即求点双连通分量中割点的数量
我们可以用dfs双连通分量求。因为每个割点一定是双连通分量中重复部分
void tarjan(int x,int f){ dfn[x]=low[x]=++num; for(int i=h[x];i;i=nx[i]){ int y=g[i]; if(y==f)continue; if(!dfn[y]){ dfs(y,x); Min(low[x],low[y]); if(dfn[x]<=low[y]){ if(!f)deg++; else cut[x]=1; } } }}void dfs(int x){ vis[x]=T; if(cut[x])return; Cnt++; for(int i=h[i];i;i=nx[i]){ int y=g[i]; if(cut[y]&&vis[y]!=T)Cut++,vis[y]=T; else if(!vis[y])dfs(y); }}int main(){ int n=0,m,a,b; scanf("%d",&m); while(m--){ scanf("%d %d",&a,&b); Max(n,a); Max(n,b); Add(a,b); Add(b,a); } for(int i=1;i<=n;i++){ if(!dfn[i]){ deg=0; tarjan(i,0); if(deg>1)cut[i]=1; } } for(int i=1;i<=n;i++){ if(!cut[x]&&!vis[x]){ Cnt=Cut=0; T++; dfs(i); if(Cut==1)ans1++,ans2*=Cnt; if(!Cut)ans1+=2,ans2*=Cnt*(Cnt-1); } }printf("%d %d",ans1,ans2);}
tip:
void tarjan(int x,int f=0){ dfn[x]=low[x]=++Dfn; stk[++top]=x; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(y==f)continue; if(dfn[y])Min(low[x],dfn[y]); else{ tarjan(y,x); Min(low[x],low[y]); if(low[y]>dfn[x]){ /*如果不是和x同一块就开始缩点*/ ++tree; while(low[stk[top]]>dfn[x])T[stk[top--]]=tree; } } }}
4 0
- tarjan算法详解
- tarjan算法详解
- Tarjan算法详解
- Tarjan算法详解
- Tarjan算法详解
- Tarjan算法详解
- Tarjan算法详解
- Tarjan 算法超级详解
- tarjan算法的详解
- Tarjan算法详解
- Tarjan算法模板 详解
- 强连通分量-tarjan算法模板详解
- 【ACM】tarjan算法详解【强连通分量】
- 强连通算法--Tarjan个人理解+详解
- ★★★★Tarjan算法详解
- tarjan算法
- Tarjan算法
- tarjan算法
- 微博 第三方登录
- 浅析=======Struts2之==========valueStack
- 特殊的不定方程——佩尔方程
- Java动态代理总结
- React-Native 之 项目实战(一)
- Tarjan算法详解
- Codeforces Round #404 (Div. 2) C题
- 如何学习C语言?学C语言有什么秘诀?
- 为控件添加动画的方法(Alpha透明度,rotate旋转,scale缩放,translate位移)
- Trie——51nod1526 分配笔名
- 有关三角形坐标面积代码
- STM32F407(5)
- Codeforces 785E 题解(树套树-树状数组套线段树)
- 170316 汇编-Debug指令、寄存器和内存