求强连通分量tarjan算法文档格式.docx
- 文档编号:21292912
- 上传时间:2023-01-29
- 格式:DOCX
- 页数:8
- 大小:185.83KB
求强连通分量tarjan算法文档格式.docx
《求强连通分量tarjan算法文档格式.docx》由会员分享,可在线阅读,更多相关《求强连通分量tarjan算法文档格式.docx(8页珍藏版)》请在冰豆网上搜索。
∙数组的初始化:
当首次搜索到点p时,Dfn与Low数组的值都为到该点的时间。
∙堆栈:
每搜索到一个点,将它压入栈顶。
∙当点p有与点p’相连时,如果此时(时间为dfn[p]时)p’不在栈中,p的low值为两点的low值中较小的一个。
∙当点p有与点p’相连时,如果此时(时间为dfn[p]时)p’在栈中,p的low值为p的low值和p’的dfn值中较小的一个。
∙每当搜索到一个点经过以上操作后(也就是子树已经全部遍历)的low值等于dfn值,则将它以及在它之上的元素弹出栈。
这些出栈的元素组成一个强连通分量。
∙继续搜索(或许会更换搜索的起点,因为整个有向图可能分为两个不连通的部分),直到所有点被遍历。
算法伪代码:
tarjan(u){ DFN[u]=Low[u]=++Index//为节点u设定次序编号和Low初值 Stack.push(u)//将节点u压入栈中 foreach(u,v)inE//枚举每一条边 if(!
dfn[v])//如果节点v未被访问过
{ tarjan(v)//继续向下找 Low[u]=min(Low[u],Low[v])
} elseif(vinS)//如果节点v还在栈内 Low[u]=min(Low[u],DFN[v]) if(DFN[u]==Low[u])//如果节点u是强连通分量的根
do{ v=S.pop//将v退栈,为该强连通分量中一个顶点 }while(u==v);
}
演示算法流程;
从节点1开始DFS,把遍历到的节点加入栈中。
搜索到节点u=6时,DFN[6]=LOW[6],找到了一个强连通分量。
退栈到u=v为止,{6}为一个强连通分量。
返回节点5,发现DFN[5]=LOW[5],退栈后{5}为一个强连通分量。
返回节点3,继续搜索到节点4,把4加入堆栈。
发现节点4向节点1有后向边,节点1还在栈中,所以LOW[4]=1。
节点6已经出栈,(4,6)是横叉边,返回3,(3,4)为树枝边,所以LOW[3]=LOW[4]=1。
继续回到节点1,最后访问节点2。
访问边(2,4),4还在栈中,所以LOW[2]=DFN[4]=5。
返回1后,发现DFN[1]=LOW[1],把栈中节点全部取出,组成一个连通分量{1,3,4,2}。
经过该算法,求出了图中全部的三个强连通分量{1,3,4,2},{5},{6}。
可以发现,运行Tarjan算法的过程中,每个顶点都被访问了一次,且只进出了一次堆栈,每条边也只被访问了一次,所以该算法的时间复杂度为O(N+M)。
此外,该Tarjan算法与求无向图的双连通分量(割点、桥)的Tarjan算法也有着很深的联系。
学习该Tarjan算法,也有助于深入理解求双连通分量的Tarjan算法,两者可以类比、组合理解。
应用例子:
(OJ1484popularcows)
题意:
有N只牛,输入a,b的话,则说明b关注a,而且关注有传递性。
例如c关注b,且b关注a,则c也关注a。
题目问有多少只奶牛能被其他所有的奶牛关注。
把题目的模型转换:
N个顶点的有向图,有M条边。
求一共有多少个点,满足这样的条件:
所有其它的点都可以到达这个点。
这个点满足条件的充要条件是:
这个点是树中唯一的出度为0的点。
先求强连通分量,然后可以把强连通分量缩成一个点,因为,在强连通分量中的任意两个点可以到达,所有的点具有相同的性质,即它们分别能到达的点集都是相同的,能够到达它们的点集也是相同的。
然后就重新构图,缩点后的图是没有强连通分量的,否则,可将环上所有点也缩成一个点,与极大强联通分量矛盾。
所以只要找出度为0的点,并且出度为0的点只有1个,如果出度为0的点有多个的话,问题则无解。
代码:
#include<
stdio.h>
string.h>
#defineadj10010
#defineedg50010
structnode
{
intv;
intnext;
};
nodeedge[edg];
nodeedge1[edg];
intlow[adj],dfn[adj],Stack[adj];
intfirst[adj],first1[adj],fuck[adj];
boolins[adj];
intn,m,temp,cnt,top,count;
intcnt_size[adj],belong[adj],outdegree[adj];
voidcreat(intu,intv)
edge1[count].next=first1[u];
edge1[count].v=v;
first1[u]=count++;
voidtarjan(intu)
inti,v;
dfn[u]=low[u]=++temp;
Stack[top++]=u;
ins[u]=true;
for(i=first[u];
i!
=-1;
i=edge[i].next)
{
v=edge[i].v;
if(!
dfn[v])
{
tarjan(v);
if(low[u]>
low[v])
low[u]=low[v];
}
elseif(ins[v])
low[u]=dfn[v];
}
if(dfn[u]==low[u])
intj;
do
top--;
j=Stack[top];
ins[j]=false;
cnt_size[cnt]++;
belong[j]=cnt;
}while(u!
=j);
cnt++;
intmain()
inti,j,k,v,sum,num;
inte=0;
scanf("
%d%d"
&
n,&
m);
memset(first,-1,sizeof(first));
for(k=0;
k<
m;
k++)建立图
scanf("
i,&
j);
edge[e].v=j;
edge[e].next=first[i];
first[i]=e;
e++;
memset(dfn,0,sizeof(dfn));
memset(ins,false,sizeof(ins));
temp=cnt=top=0;
memset(cnt_size,0,sizeof(cnt_size));
memset(low,0,sizeof(low));
for(i=1;
i<
=n;
i++)求强连通分量
dfn[i])
tarjan(i);
memset(first1,-1,sizeof(first1));
count=0;
i++)重新构造图
for(j=first[i];
j!
j=edge[j].next)
v=edge[j].v;
if(belong[i]!
=belong[v])
creat(belong[i],belong[v]);
memset(outdegree,0,sizeof(outdegree));
for(i=0;
cnt;
i++)求每个节点的出度
for(j=first1[i];
j=edge1[j].next)
outdegree[i]++;
sum=num=0;
i++)
if(outdegree[i]==0)求节点为0的个数
sum=cnt_size[i];
num++;
if(num==1)
printf("
%d\n"
sum);
else
0\n"
);
return0;
结束!
以下无正文
仅供个人用于学习、研究;
不得用于商业用途。
толькодлялюдей,которыеиспользуютсядляобучения,исследованийинедолжныиспользоватьсявкоммерческихцелях.
notforcommercialuse.
Nurfü
rdenpersö
nlichenfü
rStudien,Forschung,zukommerziellenZweckenverwendetwerden.
Pourl'
é
tudeetlarechercheuniquementà
desfinspersonnelles;
pasà
desfinscommerciales.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 求强连通分量 tarjan算法 连通 分量 tarjan 算法
![提示](https://static.bdocx.com/images/bang_tan.gif)