- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
Tarjan算法求解HOJ1007
Tarjan算法求解HOJ 1007
之前就写过Tarjan算法,但是用来求解有向图强连通分量。这次用来求关节点还用和以前一样的思路,发现好像不行。接下来分别说说用tarjan算法求解有向图强连通分量和无向图关节点。
一、tarjan算法求解有向图强连通分量
如果在有向图中两个顶点可以互相达到,称这两个顶点强连通。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的强连通子图,称为强连通分量。比如下面这个图:
5
3
1
6
4
2
子图{1,2,3,4}为一个 HYPERLINK /subview/1976645/1976645.htm \t _blank 强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。求解强连通分量的方法大致是:dfs整个图,则会生成一棵树,按照深度优先搜索的顺序给每个节点定义一个order,再定义一个low,low代表该节点在该生成树上面往上最远可以到达的节点,初始化为order。每遍历一个节点,将其压入栈中。求解强连通分量关键在于找圈。一个强连通图可以找到一个大圈,一个非强连通图可以找到几个圈。例如生成一个树:
4
3
2
1
1-2-3-1为一个圈,则代表{1,2,3}构成一个强连通分量,结点3的low值为1代表它可以向上指向节点1。对于任意节点A,它的low值可能大于它儿子S的low值,但是节点A可以到达节点S,因此也可以到达S的low值指向的节点。因此low[A]=min(low[A],low[S]).
当一个节点P的所有儿子都已遍历完,它的low值还等于order值,说明它无法到达它上面的节点,也就说明包含它的圈已经达到最大,弹出栈中节点直至栈顶节点的low与order相等,此时栈顶节点即为P,再弹出P,P所在的强连通分量即全部弹出。继续dfs,找出其他的强连通分量。
代码:
void tarjan(graph G,node v)
{
low[v.position] = dfn[v.position] = tot;
tot++;
S.push(v);
flag[v.position] = true;
edgePtr pointer = v.firstEdge;
for (; pointer != NULL; pointer = pointer-next)
{
node w = G.points[pointer-position];
if (dfn[pointer-position] == 0)
{
tarjan(G, G.points[pointer-position]);
low[v.position] = min(low[v.position], low[w.position]);
}
else if (flag[w.position])
low[v.position] = min(low[v.position], low[w.position]);
}
if (low[v.position] == dfn[v.position])
{
cout 第 number 个强连通分量:;
while (low[S.top().position] != dfn[S.top().position])
{
cout v S.top().position ;
flag[S.top().position] = false;
S.pop();
}
cout v S.top().position \n;
flag[S.top().position] = false;
S.pop();
number++;
}
}
有两行将弹出节点置为false,即flag[S.top().position] = false;。是因为若不将其置为false,可能有在之后其它分支上的节点会指向其中某一个已弹出节点,就会执行以下代码:
else if (flag[w.position])
low[v.position] = min(low[v.position], low[w.position]);
那么就会将已弹出节点弄到现在要找的强连通分量。而已弹出节点不应该再出现,不应该再进行任何操作。第一个条件是 dfn[pointer-position] == 0,第二个条件flag[w.position].对于已弹出节点不满足任何一个条件,因此不进行任何操作。已弹出节点不应该再出现,这是因为一个节点既然已经被弹出,就说明它在一个强连通分量上,那么它就不可能再出现在另一个强连通分量上,
文档评论(0)