【算法概论】3.图的分解
来源:互联网 发布:访客网络设置上网时间 编辑:程序博客网 时间:2024/06/02 08:10
3 图的分解
3.1 为什么是图
图的表示:
当|E|接近|V|时,稀疏图;当|E|接近|V|2时,稠密图。 - 邻接表:
|V|个链表,遍历u的链表确定边(u,v)是否存在;占据O(|E|)空间。 - 邻接矩阵:
O(1)内确定边是否存在,占据O(n2)的空间。
- 邻接表:
3.2 无向图的深度优先搜索
- “边”的分类:树边、回边
- “深度优先搜索”树
procedure explore(v) Input: G=(V,E) is a graph;v ∈ V Output:visited(u) is set to true for all nodes u reachable from v visited(v)=true; previsit(v) for each edge (v,u) ∈ E if not visited(u): explore(u) postvisit(v)
- “深度优先搜索”森林,复杂度
O(|V|+|E|)
procedure dfs(G) for all v ∈ V visited(v)=false for all v ∈ V if not visited(v): explore(v)
- 无向图的连通性:一个无向图是连通的当且仅当在任意两个定点之间存在一条可达路径
- 连通部件(connected component)测试
procedure previsit(v) Input: cc - 初始化为0,dfs每次调用explore(v)加1 ccnum[v] - 存储顶点v的连通部件号 ccnum[v]=cc
- 前序和后序时间戳:初始时钟clock设置为1
procedure previsit(v) //v顶点进栈时间 pre[v]=clock clock=clock+1procedure postvisit(v)//v顶点出栈时间 post[v]=clock clock=clock+1
3.3 有向图的深度优先搜索
边(u,v)的分类
- 树边:DFS森林的组成部分[u [v v] u]
- 前向边:DFS树中从一个顶点指向其叶子节点的边[u [v v] u]
- 回边:DFS树中从一个顶点指向其祖先的边[v [u u] v]
- 横跨边:指向一分支的子节点的边 [v v ]、[u u]
有向无环图:存在一个环,当且仅当深度优先搜索过程中探测到一条回边
3.4 强连通部件
- 强连通部件:有向图中,u到v、v到u均存在路径
- 强连通部件组成超级节点,对应的图为“有向无环图”(“有向无环图”能够被线性化)
3.4.1 有向图的强连通部件的分解
Korasaju算法
Kosaraju算法的分析和证明_silverbullettt
原理:一个图的强连通部件与它的反向图的强连通部件相同。
![3.1 图的分解强连通部件](3.1 图的分解强连通部件.png)
//Kosaraju算法邻接矩阵实现static int cnt, cntR, pre[MAXV], post[MAXV];static int num = G->V;//顶点个数int Kosaraju(Graph G){ int v; //初始化全局变量 cnt = cntR = 0; for (v = 0; v < num; ++v) { pre[v] = post[v] = -1; } //第一次DFS,计算逆图的后序编号 for (v = 0; v < num; ++v) { if (pre[v] == -1) dfsPOST(G, v); } cnt = 0; for (v = 0; v < num; ++v) { G->sv[v] = -1; //G->sv[v] 表示顶点v的强连通分量编号 } //第二次DFS,强连通分量编号 for (v = num - 1; v >= 0; --v) { if (G->sc[post[v]] == -1) { dfsSC(G, post[v]); ++cnt;//对一棵树编号之后计数器值加1 } } return cnt;//返回强连通分量个数}void dfsPOST(Graph G, int v) //对逆图后序编号{ int t; pre[v] = cnt++; for (t = 0; t < num; ++t) { if (G->adj[t][v] == 1) { //G->adj[t][v]逆图的边 if (pre[t] == -1) //搜索的顶点顺序:节点是否访问 dfsPOST(G, t); } } post[cntR++] = v;}void dfsSC(Graph G, int v){ int t; G->sc[v] = cnt; for (t = 0; t < num; ++t) { if (G->adj[v][t] == 1) { if (G->sc[t] == -1) //搜索的顶点顺序:逆图后序编号的逆序 dfsSC(G, t); } }}int GraphSC(Graph G, int s, int t){ return G->sc[s] == G->sc[t];}
Tarjan算法
algorithm tarjan is input:graph G=(V,E) output:set of strongly connected componentsindex:=0S:=emptyfor each v in V do if(v.index is undefined) then strongconnect(v) end ifend forfunction strongconnect(v) //Set the depth index for v to the smallest unsed index v.index:=index v.lowlink:=index index:=index+1 S.push(v) v.onStack:=true //Consider successors of v for each(v,w) in E do if(w.index is undefined) then //Successor w has not yet been visited;recurse on it strongconnect(w) v.lowlink:=min(v.lowlink,w.lowlink) else if(w.onStack) then //Successor w is in stack S and hence in the current SCC v.lowlink:=min(v.lowlink,w.lowlink) end if end for //If v is a root node,pop the stack and genetate an SCC if(v.lowlink==v.index) then start a new strongly connected component repeat w:=S.pop() w.onStack:=false add w to current strongly connected component while(w!=v) output the current strongly connected component end ifend function
Gabow算法
The algorithm performs a depth-first search of the given graph G, maintaining as it does two stacks S and P (in addition to the normal call stack for a recursive function). Stack S contains all the vertices that have not yet been assigned to a strongly connected component, in the order in which the depth-first search reaches the vertices. Stack P contains vertices that have not yet been determined to belong to different strongly connected components from each other. It also uses a counter *C*of the number of vertices reached so far, which it uses to compute the preorder numbers of the vertices.
When the depth-first search reaches a vertex v, the algorithm performs the following steps:
- Set the preorder number of v to C, and increment C.
- Push v onto S and also onto P.
- For each edge from v to a neighboring vertex w:If the preorder number of w has not yet been assigned, recursively search w;Otherwise, if w has not yet been assigned to a strongly connected component:Repeatedly pop vertices from P until the top element of P has a preorder number less than or equal to the preorder number of w.
- If v is the top element of P:Pop vertices from S until v has been popped, and assign the popped vertices to a new component.Pop v from P.
The overall algorithm consists of a loop through the vertices of the graph, calling this recursive search on each vertex that does not yet have a preorder number assigned to it.
- 【算法概论】3.图的分解
- 算法概论的思维导图
- 算法概论的思维导图
- 《算法概论》目录的思维导图
- 《算法概论》的思维导图
- 关于《算法概论》的思维导图
- 《算法概论》的思维导图
- 算法概论的思维导图
- 算法概论的思维导图
- 关于《算法概论》的思维导图
- 图算法概论
- 算法概论第一次作业之算法概论思维导图
- 算法概论思维导图
- 《算法概论》思维导图
- 《算法概论》思维导图
- 《算法概论》思维导图
- 《算法概论》思维导图
- 《算法概论》思维导图
- 【算法概论】2.分治算法
- 关键字 - static
- 字符串匹配算法KMP详细解释——深入理解
- recv recvfrom
- SVN服务器的本地搭建和使用
- 【算法概论】3.图的分解
- ubuntu 自动编译
- 一个小例子看懂java对象初始化执行过程
- 【C#】—颗粒归仓
- single summer in Odori Car park
- Angular2 之 单元测试
- oracle--PLSQL自动替换
- 服务端技术进阶(五)分布式系统解决之道:目录、消息队列、事务系统及其他
- IOS快捷键