Tarjan算法求桥和割点
来源:互联网 发布:工程算量软件 编辑:程序博客网 时间:2024/06/04 18:43
预备定义:
low[u]定义为u或者u的子树中能够通过非父子边追溯到的最早的节点的DFS开始时间
d[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)为桥
注意:找桥的时候,要注意看有没有重边。有重边,则不是桥。例题:POJ 1253 SPF
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int u,v,Case,times,flag,edgenum,col[10005],vet[10005],head[10005],nnext[10005],d[10005],low[10005],cuts[10005];
void init()
{
flag=1;
edgenum=0;
for (int i=0;i<=1005;i++)
col[i]=low[i]=d[i]=cuts[i]=vet[i]=nnext[i]=0,head[i]=-1;
times=1;
}
void Addedge(int u,int v)
{
vet[++edgenum]=v;
nnext[edgenum]=head[u];
head[u]=edgenum;
}
int Tarjan_CutPoint(int u)
{
low[u]=d[u]=times++;
for (int e=head[u],v;~e;e=nnext[e])
{
v=vet[e];
if (!d[v])
{
Tarjan_CutPoint(v);
low[u]=min(low[u],low[v]);
if (low[v]>=d[u])
cuts[u]++;
}
else
low[u]=min(low[u],d[v]);
}
return 0;
}
int main()
{
// freopen("spf.in","r",stdin);
// freopen("spf.out","w",stdout);
ios::sync_with_stdio(false);
while (cin >> u,u)
{
init();
cin >> v;
Addedge(u,v);
Addedge(v,u);
while (cin >> u,u)
{
cin >> v;
Addedge(u,v);
Addedge(v,u);
}
for (int i=1;i<1001;i++)
{
if (head[i]==-1)
break;
if (!d[i])
Tarjan_CutPoint(i);
}
cout << "Network #" << ++Case << endl;
for (int i=1;i<1001;i++)
if (i==1)
{
if (cuts[i]>=2)
cout << " SPF node 1 leaves " << cuts[1] << " subnets" << endl,flag=0;
}
else
if (cuts[i])
{
flag=0;
cout << " SPF node " << i << " leaves " << cuts[i]+1 << " subnets" << endl;
}
if (flag)
cout << " No SPF nodes" << endl;
cout << endl;
}
cout << endl;
return 0;
}
求桥的代码(也可以和上面的合并,毕竟判断条件差不多)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
int n,m,times,bridge,edgenum,head[10005],nnext[10005],cut[10005],vet[10005],low[10005],d[10005],cuts[10005];
void init()
{
edgenum=0;
memset(head,-1,sizeof(head));
}
void Addedge(int u,int v)
{
vet[++edgenum]=v;
nnext[edgenum]=head[u];
head[u]=edgenum;
cuts[edgenum]=0;
}
void Tarjan(int u,int fa)
{
int v;
low[u]=d[u]=++times;
int son=0;
for(int e=head[u];e!=-1;e=nnext[e])
{
v=vet[e];
if (v==fa)
continue;
if (!d[v])
{
son++;
Tarjan(v,u);
low[u]=min(low[u],low[v]);
if (low[v]>d[u])
{
bridge++;
cuts[e]=1;
cuts[e^1]=1;
}
if (u!=fa && low[v]>=d[u])
cut[u]=1;
}
else if (low[u]>d[v])
low[u]=d[v];
}
if (u==fa && son>1)
cut[u]=1;
}
int main()
{
froepen("bridge.in","r",stdin);
freopen("bridge.out","w",stdout);
ios::sync_with_stdio(false);
cin >> n >> m;//点数和边数
init();
for(int i=1,u,v;i<=m;i++)
{
cin >> u >> v;
Addedge(u,v);
Addedge(v,u);
}
for(int i=1;i<=n;i++)
if (!d[i])
Tarjan(i,i);
vector< pair<int,int> > ans;
for(int u=1;u<=n;u++)
for(int e=head[u];e!=-1;e=nnext[e])
if (cuts[e] && vet[e]>u)
ans.push_back(make_pair(u,vet[e]));
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
cout << ans[i].first << " " << ans[i].second << endl;
return 0;
}
- Tarjan算法求桥和割点
- 求桥和割点的Tarjan算法
- 割点和桥---Tarjan算法
- tarjan算法--求无向图的割点和桥
- tarjan算法--求无向图的割点和桥
- Tarjan算法--求无向图的割点和桥
- Tarjan求无向图桥和割点
- tarjan求桥及割点
- tarjan算法应用之割边和割点
- hihoCoder1183 tarjan算法应用之割边和割点
- Tarjan算法求割,桥,块(点双连通分支),边双连通分支总结
- tarjan算法之 割边,割点
- Tarjan求桥和割点与双连通分量【未成形】
- Tarjan算法求BCC(无向图连通块、割边、割点)
- tarjan算法求联通块中求割点和割边
- Tarjin算法求桥和割点模板
- Tarjan算法求解一个无向图中的割点和桥问题
- 超详细Tarjan算法总结,求强连通分量,割点,割边,有重边的割边
- 100_容器_List_ArrayList_LinkedList_Vector用法_详解
- 用malloc函数实现一维数组的模拟
- caffe绘制训练过程的loss和accuracy曲线
- 写一个函数,判断一个字符串是否为回文联
- 线程安全队列(三)
- Tarjan算法求桥和割点
- Git基础教程
- 进程、线程与协程
- echarts3--tooltip-position
- 《大话数据结构》第四章 队列
- mysql 实现 substring+lastindexof 的方法
- 关于变量交换(异或)
- HDU 5127 Dogs' Candies(瞎暴力)
- 安全线程队列(四)