求桥和割点的Tarjan算法
来源:互联网 发布:大数据分析工程师 编辑:程序博客网 时间:2024/05/16 01:31
low[u]定义为u或者u的子树中能够通过非父子边追溯到的最早的节点的DFS开始时间
dfn[u]表示dfs下u的开始时间
割点:无向连通图中,如果删除某点后,图变成不连通,则称该点为割点。
桥:无向连通图中,如果删除某边后,图变成不连通,则称该边为桥。
判断割点方法:
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得dfn(u)<=low(v)。
也就是u的子树中的v点无法到达u之前的点,所以u点去掉就是两个连通分支,所以u为割点
判断桥的方法:
一条边(u,v)是桥,当且仅当(u,v)为树枝边(即非负边),且满足dfn(u)<low(v)(前提是其没有重边)。
也就是,u的儿子v之间只有一条边(前提是无重边),且v点只能到v点到不了v点前,所以(u,v)边去掉就是两个连通分支,所以(u,v)为桥
注意:找桥的时候,要注意看有没有重边。有重边,则不是桥。
以下为代码:
割点和桥保存在cutvex和bridge中
1)在Tarjan算法的时候直接找桥割点:
#include<iostream>#include<cstdio>#include<vector>#include<stack> #include<cstring>#include<algorithm>using namespace std;const int maxn=10000+10;typedef pair<int,int> Edge; int index=0,rootson=0; vector<bool> vis(maxn); vector<int> dfn(maxn),low(maxn),cutvex;vector<vector<int> > G(maxn); vector<Edge> bridge;void Tarjan(int u,int father){dfn[u]=low[u]=++index;vis[u]=true;bool isCut=false;for(int i=0;i<G[u].size();i++){int v=G[u][i];if(!vis[v]){Tarjan(v,u);low[u]=min(low[u],low[v]);if(dfn[u]<low[v]) bridge.push_back(Edge(u,v));if(dfn[u]<=low[v]) isCut=true;}else if(father!=v) //只能由非父子边更新 low[u]=min(low[u],dfn[v]);}if(father==1&&rootson!=-1) rootson++;if(rootson>1) cutvex.push_back(1),rootson=-1; if(u!=1&&isCut)cutvex.push_back(u);}int main(){int n,m;cin>>n>>m;while(m--){int u,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}Tarjan(1,0); //联通的sort(cutvex.begin(),cutvex.end());sort(bridge.begin(),bridge.end());for(int i=0;i<cutvex.size();i++)cout<<cutvex[i]<<endl;for(int i=0;i<bridge.size();i++)cout<<bridge[i].first<<','<<bridge[i].second<<endl;return 0;}
2)先把数据保存下来,再找桥割点:
#include<iostream>#include<cstdio>#include<vector>#include<stack> #include<cstring>#include<algorithm>using namespace std;const int maxn=10000+10;typedef pair<int,int> Edge; int index=0; vector<bool> vis(maxn); vector<int> dfn(maxn),low(maxn),Father(maxn),cutvex;vector<vector<int> > G(maxn); vector<Edge> bridge;void Tarjan(int u,int father){dfn[u]=low[u]=++index;Father[u]=father;vis[u]=true;for(int i=0;i<G[u].size();i++){int v=G[u][i];if(!vis[v]){Tarjan(v,u);low[u]=min(low[u],low[v]);}else if(father!=v) //只能由非父子边更新 low[u]=min(low[u],dfn[v]);}}int Count(int n){int nson=0; //根节点的子树Tarjan(1,0);for(int v=2;v<=n;v++) //1为根 {int u=Father[v];if(u==1) nson++;else if(dfn[u]<=low[v]) cutvex.push_back(u);} //v到不了u之前的点if(nson>1) cutvex.push_back(1);sort(cutvex.begin(),cutvex.end());for(int u=1;u<=n;u++){int v=Father[u];if(v>0&&dfn[v]<low[u]) bridge.push_back(Edge(v,u));} }int main(){int n,m;cin>>n>>m;while(m--){int u,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}Tarjan(1,0); //联通的Count(n);for(int i=0;i<cutvex.size();i++)cout<<cutvex[i]<<endl;for(int i=0;i<bridge.size();i++)cout<<bridge[i].first<<','<<bridge[i].second<<endl;return 0;} int main(){int n,m;cin>>n>>m;while(m--){int u,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}Tarjan(1,0); //联通的Count(n);for(int i=0;i<cutvex.size();i++)cout<<cutvex[i]<<endl;for(int i=0;i<bridge.size();i++)cout<<bridge[i].first<<','<<bridge[i].second<<endl;return 0;}
0 0
- Tarjan算法求桥和割点
- 求桥和割点的Tarjan算法
- tarjan算法--求无向图的割点和桥
- tarjan算法--求无向图的割点和桥
- Tarjan算法--求无向图的割点和桥
- 割点和桥---Tarjan算法
- Tarjan求无向图桥和割点
- tarjan求桥及割点
- 超详细Tarjan算法总结,求强连通分量,割点,割边,有重边的割边
- tarjan算法应用之割边和割点
- hihoCoder1183 tarjan算法应用之割边和割点
- 关于tarjan算法的一些理解(割边和割点)
- poj1523—SPF(tarjan算法求无向图中所有的割点)
- Tarjan算法求割,桥,块(点双连通分支),边双连通分支总结
- tarjan算法之 割边,割点
- Tarjan求桥和割点与双连通分量【未成形】
- Tarjan算法求BCC(无向图连通块、割边、割点)
- tarjan算法求联通块中求割点和割边
- Qt之QNetworkAddressEntry
- Android逆向工程-第三部分
- 快速开发数据分析系统
- Unix 环境编程: 进程控制
- linux驱动-I2C设备
- 求桥和割点的Tarjan算法
- GM11 C语言实现
- 聊一聊Netty TCP粘包/拆包问题的解决办法
- DSO(dsoframer)的接口文档在VC++使用
- [LeetCode]--131. Palindrome Partitioning(backTracking && DFS && DP)
- Effective Java之对所有对象通用的方法
- Observer模式
- 【Java 并发系列】深入分析Volatile的实现原理
- 后缀表达式