1. 1、本文档共35页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
图论(lrj)

《算法艺术与信息学竞赛》 第二版 教学幻灯片——图论算法 第五讲 连通性问题 (刘汝佳) 内容介绍 一、有向图: SCC划分的Kosaraju算法 二、有向图: SCC划分的Tarjan和Gabow算法 三、无向图: 割顶和桥的判定 四、无向图: BCC划分 一、Kosaraju算法 SCC的概念 有向图中, u可达v不一定意味着v可达u. 相互可达则属于同一个强连通分量(Strongly Connected Component, SCC) 有向图和它的转置的强连通分量相同 所有SCC构成一个DAG Kosaraju算法 算法步骤 调用DFS(G), 计算出每个结点的f[u] 计算GT 调用DFS(GT), 在主循环中按照f[u]递减的顺序执行DFS-VISIT, 则得到的每个DFS树恰好对应于一个SCC 运行时间:O(n+m) 算法示例: 先把f[u]排序成postI数组, 然而在GT上DFS Kosaraju算法的正确性 当按照f值排序以后, 第二次DFS是按照SCC的拓扑顺序进行(以后所指d[u]和f[u]都是第一次DFS所得到的值) 记d(C)和f(C)分别表示集合U所有元素的最早发现时间和最晚完成时间, 有如下定理: 定理: 对于两个SCC C和C’, 如果C到C’有边, 则f(C)f(C’) 情况一: d(C) d(C’), 考虑C中第一个被发现的点x, 则C’全为白色, 而C到C’有边, 故x到C’中每个点都有白色路径. 这样, C和C’全是x的后代, 因此f(C) f(C’) 情况二: d(C) d(C’). 由于从C’不可到达C, 因此必须等C’全部访问完毕才能访问C. 因此f(C) f(C’) 推论:对于两个SCC C和C’, 如果在GT中C到C’有边, 则f(C)f(C’) Kosaraju算法的正确性 首先考虑f(C)最大的强连通分量. 显然, 此次DFS将访问C的所有点, 问题是是否可能访问其他连通分量的点? 答案是否定的, 因为根据推论, 如果在GT中C到另外某个C’存在边, 一定有f(C)f(C’), 因此第一棵DFS恰好包含C. 由数学归纳法可知, 每次从当前强连通分量出发的边一定连到f值更大的强连通分量, 而它们是已经被遍历过的, 不会在DFS树形成多余结点 SCC图 把SCC看成点, 则DFS的同时可以得到SCC图. 在第二次DFS中, 每新开始一次DFS-VISIT, 即新找到一个SCC, 当前编号加1. DFS-VISIT某个SCC C时, 如果出现了指向一个已访问过的SCC C’的交叉边, 则在SCC图中设置边(C’, C), 因为在转置图中存在C到C’的边 局限性 SCC算法的简单历史 第一个SCC算法: Tarjan 1972 (经典算法) 80年代: 精美的Kosaraju算法 (后来发现和1972年苏联发现的算法本质相同) 1999 Gabow在60年代的思想上提出了第三个线性算法 局限性: Kosaraju算法需要计算图的转置和两次DFS, 时间效率不如Tarjan算法和Gabow算法 二、Tarjan算法和Gabow算法 基于DFS的SCC算法 结点放在栈S中 当一个点结束后,它所在的SCC就访问完成了 但是若任意点都可以输出SCC, 会引起重复 我们把输出任务交给SCC中pre最小的一个 如何判断输出任务由谁完成呢? 条件: 如果u或者u的后代存在一条反向边(w, v)到达u的祖先v, 那么u和父亲属于同一个SCC, 且由于pre[v]pre[u], 任务不可能需要u完成 Tarjan算法: 使用LOW函数测试该条件 Gawbow算法: 使用另一个栈 Tarjan算法 Tarjan算法: 定义辅助函数low[u]为u及其的后代所能追溯到的最早(最先被发现)祖先点v的pre[v]值, 则可以在计算low的同时完成SCC计算 检查完儿子和检查反向边时更新low函数, 交叉边可以通过特殊手段避免 LOW函数的计算 min = low[u] = pre[u] = cnt++; //初始为pre[u] S.push(u); for u的邻居v { //计算min if (pre[v] == -1) dfs-visit(v); if (low[v] min) min = low[v]; } if (min low[u]) { low[u] = min; return; } //任务不用u完成 do { id[v = S.pop()] = scnt; low[v] = n; } while (v != u); scnt++; 注意: 输出SCC后需要设置low值均为最大值n以防止交叉边影响结果 LOW函数的计算 Gabow算法 Gabow算

文档评论(0)

xxj1658888 + 关注
实名认证
内容提供者

教师资格证持证人

该用户很懒,什么也没介绍

领域认证该用户于2024年04月12日上传了教师资格证

1亿VIP精品文档

相关文档