无向图的tarjan算法
Posted oieredsion
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无向图的tarjan算法相关的知识,希望对你有一定的参考价值。
-无向图求点双联通分量 并求单环
将桥和割点分开讨论
注意判断根是否为割点
stack<int> W;
ll f[maxnn];
int scc=0;
ll sum[maxnn];
int ttt[maxnn];
int ma[maxnn],mi[maxnn];
void tarjan(int v,int fa) {
int r;
mark[v]=1;
dfn[v]=low[v]=++vis;
W.push(v);
for(int i=las[v]; i; i=nex[i]) {
int u=en[i];
int d;
if(u!=fa) {
if(!dfn[u]) {
tarjan(u,v);
low[v]=min(low[v],low[u]);
if(dfn[v]==low[u]) {
scc++;
mi[scc]=v;
rrr[scc]=1;
ma[scc]=v;
do {
d=W.top();
rrr[scc]++;
mi[scc]=min(mi[scc],d);
ma[scc]=max(ma[scc],d);
W.pop();
} while(d!=u);
}
if(dfn[v]<low[u]) {
do {
d=W.top();
W.pop();
} while(d!=u);
}
} else {
low[v]=min(low[v],dfn[u]);
}
}
}
}
int Tarjan(int u, int fa)
{
int low[u] = dfn[u] = ++Time;
for(int i = Last[u]; i; i = Next[i])
{
Son[u]++;
int v = End[i];
if(!dfn[v])
{
s.push(i); //i号边入栈, i是一条父子边(树枝边)
Tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) //对于v而言,u是割点,找到一个点双连通分量
{
CutPoint[u] = true; //将u标记为是割点
BCC++; //统计双连通分量的个数
while(true)
{
int k = s.top(); s.pop(); //弹出栈顶边, 编号为k
int x=Start[k]; int y=End[k]; //x,y分别为k号边的两个端点
if(Belong[x]!=BCC) //Belong[x]记录目前x属于那个双连通块
{ Block[BCC].push_back(x); Belong[x]=BCC; } //Block[BCC]存储属于BCC号联通块的节点的编号
if(Belong[y]!=BCC)
{ Block[BCC].push_back(y); Belong[y]=BCC; }
if(x==u && y==v )break; //对于v,u是割点,那么v肯定不属于当前连通块
}
}
}e
lse if(dfn[v] < dfn[u] && v != fa) //i是一条返祖边
{
s.push(i);
low[u] = min(low[u], dfn[v]);
}
}i
f(fa == 0 && Son[u] <= 1) CutPoint[u] = false; //前面可能误把根当作了割点。 若i为根, 且儿子个数<=1,i不是割点。
}
-无向图求边双联通分量 强行变成有向图
stack<int > S;
int sec;
inline void tarjan(int v,int e) {
dfn[v]=low[v]=++vii;
S.push(v);
for(int i=las[v]; i; i=nex[i]) {
if((e!=-1)&&((i^1)==(e))) {
continue;
}
ll u=en[i];
if(!dfn[u]) {
tarjan(u,i);
low[v]=min(low[u],low[v]);
} else {
low[v]=min(low[v],dfn[u]);
}
}
ll r;
if(low[v]==dfn[v]) {
sec++;
do {
r=S.top();
S.pop();
belong[r]=sec;
ttt[sec]++;
} while(r!=v);
}
}
以上是关于无向图的tarjan算法的主要内容,如果未能解决你的问题,请参考以下文章