tarjan算法
来源:互联网 发布:ai寻路算法 编辑:程序博客网 时间:2024/05/16 09:38
tarjan算法是一种求强联通分量的算法,通过访问节点遍历。有几个比较重要的知识:
强联通分量:如果一个集合中的所有的节点都可以互相到达,那么这个集合就是一个强联通分量。
dfn【i】:记录节点i第几个被访问。
low【i】:记录节点i可以追溯到的最早的祖先
zh【i】:栈中第i个元素
vis【i】:记录i是否在栈中
首先,寻找没有更新过dfn的节点开始tarjan:
1、更新dfn【f】与low【f】,将f入栈
2、寻找与i相连的节点v
3、如果节点v没有被访问,那么tarjan v low low[f]=min(low[f],low[v]);(强联通分量两点相连,因此下级的节点会找到先前被搜过的节点)
4、如果节点v被访问过且在栈中,那么low[f]=min(low[f],dfn[v]),即下级的节点会找到先前被搜过的节点
ps:这里的low也可以用low[f]=min(low[f],low[v])更新
5。若f的dfn与low相等,即f为某个强联通分量的第一个被访问的节点,那么就弹出栈中比f入栈晚的节点输出
代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int dfn[100001],low[100001],a,b,c,head[100001],cnt,tot,top,siz,zh[100001],vis[100001];
struct node{
int to,next;
}edge[100001];
int add(int s,int t)
{
edge[++cnt].to=t;
edge[cnt].next=head[s];
head[s]=cnt;
}
int find(int f)
{
tot++;top++;
dfn[f]=low[f]=tot;
vis[f]=1;zh[top]=f;
for(int i=head[f];i!=0;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
find(v);low[f]=min(low[f],low[v]);
}
else if(vis[v]) low[f]=min(low[f],dfn[v]);
}
if(dfn[f]==low[f])
{
siz++;
while(f!=zh[top])
{
// cout<<zh[top]<<" ";
top--;
}
vis[f]=0;//cout<<f<<endl;
top--;
}
}
int main()
{
while(cin>>a>>b)
{
siz=cnt=tot=top=0;
for(int i=1;i<=b;i++)
{
int x,y;cin>>x>>y;add(x,y);
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=a;i++)
{
if(!dfn[i]) find(i);
}
}
}