求桥和割点的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
原创粉丝点击