算法分析与设计——无向图的应用(C++版)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

cn ww VertexType adjvex;
. w VRType
lowcost;
w} closedge[MAX_VERTEX_NUM];
wwint i,j,k;
t k = LocateVex ( G, u );
ne for ( j=0; j<G.vexnum; ++j )
k. {
// 辅助数组初始化Biblioteka Baidu
k b }
oo cn }
nb w. } // PRIM c w 对图 1 所示的图,应用 Prim 算法,将边加入集合 T 的过程如图 2 所示。
. ww.cnbook.net w www.cnbook.net 图 2 Prim算法的运行流程 w 为了便于在集合 U 和 V=U 之间选择最小的边,建立两个数组 CLOSET 和 LOWCODT, net ok CLOSEST[i]表示 U 中的一个顶点,该顶点和 V-U 中的一个顶点构成的边(i, CLOSEST[i]具有最小 k. bo 的权;LOWCOST[i]表示边 CLOSEST[i])的权,i=2, …, n。 o n 算法的每一步扫描数组 LOWCOST,在 V-U 中找出离 U 最近的顶点,令其为 k,并打印边(K, bo .c CLOSEST[K])。然后修改数组 LOWCOST 和 CLOSEST,标记 k 已经加入 U。用 C 表示图的邻接矩 cn ww 阵,C[i, j]和 C[j, i]是边(i, j)的权,如果不存在边(i, j),则 C[i, j]的值为一个大于任何权而小于无限大 . w 的常数。 w 在执行 Prim 算法时,第 2 个 for 循环执行 n-1 次。第 3 和第 4 行的 for 循环,其执行时间都是 ww O(n)。所以,Prim 算法总的执行时间是 O(n2)。当 n 很大时,Prim 算法消耗很大。所以,本算法一 t 般用于的顶点不太多的情况。另外,由于 Prim 算法与图中边数无关,该算法适合于稠密图。 ne 构造最小耗费生成树的另一种常用的方法是 Kruskal 算法,当图中的边数为 e 时,Kruskal 算法 k. 所需的时间为 O(eloge)。当 e 与 n2 差不多大小的时候,Prim 算法比 Kruskal 算法好,但当 e 远远小 oo c 于 n2 时 Kruskal 算法却比 Prim 算法好的多,换句话说,Kruskal 算法的时间主要取决于边数,它较 nb w. 适合于稀疏图。 .c ww 1.3 Kruskal 算法 ww Kruskal 算法所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加 w t 入已选择的边的集合中。它的基本思想是:设有一个有 n 个顶点的连通网络 G=(V, E),其中 V={1, ook.ne ※ 3 ※
www.cnbook 算法分析与设计——无向图的应用(C++版)
net 内容提要:本文主要介绍了无向图的应用示例。主要讨论关于无向图的最小生成树、无向图的 et k. 遍历问题、图与图匹配和迷宫问题。首先介绍了关于最小生成树的基本定义和性质,以及两种构造 .n oo 最小生成树的算法(Prim 算法和 Kruskal 算法)。然后,和有向图相似的介绍了两种无向图的遍历方 k b 法(深度优先遍历和广度优先遍历)。接着介绍了迷宫问题的求解方法。最后,介绍了求解最短路径 o cn 的六种方法,包括宽度优先搜索、动态规划、A﹡算法、等代价搜索法、Warshall 算法和标号法。
book .cnb 这里:
W (T ) = ∑ w(u,v) ( u , v )∈TE
cn ww TE 表示 T 的边集。 . w w(u, v)表示边(u, v)的权。 ww 权最小的生成树称为 G 的最小生成树。最小生成树可简记为 MST。 w 从一个带权的连通图(即网络),如何找出一棵生成树,使得各边上的权值总和达到最小,这是
w. w 1.1 最小生成树性质
ww 最小生成树具有如下性质:设 G=(V, E)是一个连通图,在 E 上定义一个函数,令 U 是顶点集 V ook.net ※ 1 ※
.cnbook 的一个真子集。若(u, v)是 G 中所有的一个端点在 U(u∈U)里、另一个端点不在 U(即 v∈V-U)里 ww 的边中,具有最小权值的一条边,则一定存在 G 的一棵最小生成树包括此边(u, v)。根据这一性质 w t (MST 性质),可以构造最小生成树。
.cnbook 2, …, n},C 是关于 E 中每条边的权函数。最初先构造一个只有 n 个顶点,没有边的非连通图 T=(V, ww O),图中每个顶点自成一个连通分量,即图 T 由 G 中的 N 个顶点构成,没有任何一个边。然后, w t 按照边的权递增的顺序,依次考查 E 中的每条边。当在 E 中选到一条具有最小权值的边时,若该边 e 的两个顶点落在不同的连通分量上,则将此边加入到 T 中;否则将此边舍去,重新选择一条权值最 t .n 小的边。如此重复下去,当 T 中的连通分量的个数为 1 的时候,说明 V 中的全部顶点通过 E 中权最 ne ok 小的那些边,构成了一个没有环路的连通图 T,即图 G 的最小生成树。 . o Kruskal 算法描述如下: ok nb KruskalMST(G)
t .n 构造最小生成树典型的方法有两种:克普里姆(Prim)算法和鲁斯卡尔(Kruskal)算法,它们 e k 都采用了一种逐步求解的策略。
k.n boo 1.2 Prim 算法
oo cn 根据最小生成树的性质,由加权图G=(V, E)构造最小生成树的一种算法,即Prim算法。Prim算 nb w. 法的执行非常类似于寻找图的最短通路的Dijkstra算法。Prim算法的特点是集合A中的边总是只形成 .c ww 单棵树。
w. 关键字:无向图、最小生成树、Prim 算法、Kruskal 算法、迷宫问题、最短路径 ww 引言:无向图 G=(V, E)由顶点的集合 V 与边的集合 E 组成。无向图和有向图的区别在于,构成 t 无向图任意一条边的两个顶点是无序的,就是说,如果(V, W)是一条无向边,(V, W)=(W, V),以后 ne 把无向图简称图。许多学科都用图描述对象之间的关系,建立数据模型,图的每个顶点表示一个对 t . 象,每条边表示两个对象之间的关系。 ne ok 正文:
.c { //求连通网 G 的一棵 MST ww T=(V,E); //初始化,T 是只含 n 个顶点不包含边的森林 w //依权值的递增序对 E(G)中的边排序,并设结果在 E[0..e-1]中 et for(i=0;i<e;i++) t .n { //e 为图中边总数 e k 取 E[0,e-1)中的第 i 条边(u,v); .n oo if u 和 v 分别属于 T 中两棵不同的树 then
k. 如果网络 G 表示 n 个城市之间的通信线路网线路,其中顶点表示城市,边表示两个城市之间的
oo c 通信线路,边上的权值表示线路的长度或造价,就可以建立一个通信网络。对于这样一个有 n 个顶
nb w. 点的网络,可以有不同的生成树,每一棵生成树都可以构成通信网络。希望能够根据各条边上的权
c w 值,选择一棵总造价最小的生成树,这就是构造网络的最小(代价)生成树的问题。
ww Prim 具体算法如下所示:
w void PRIM(MGraph G, VertexType u)
net ok { . o // 用普里姆算法从第 u 个顶点出发构造网 G 的最小生成树 T,输出 T 的各条边 ok nb // 记录从顶点集 U 到 V-U 的代价最小的边的辅助数组定义
bo .c struct {
net ok 一个有实际意义的问题。
. o 【例 1】在 n 个城市之间建立通信网络,至少要架设 n-1 条线路。这时自然会考虑:如何做才 ok nb 能使得总造价最少?
bo .c 图 1(a)是一个带权图 G,(b)是该图的最小生成树。
www.cn t www (a)
(b)
ne 图 1 图和它的生成树
t Prim 算法的基本思想如下:假设 G=(V, E)是连通网,生成的最小生成树为 T=(V, TE),求 T 的 ne 步骤如下:
et k. (1)初始化:U={u0},TE={φ}。 n o (2)在所有 u∈U,v∈V-U 的边(u, v)∈E 中,找一条权最小的边(u0, v0),TE+{(u0, v0)}→TE, k. bo {v0}+U→U。 oo cn (3)如果 U=V,则算法结束;否则重复(2)。 b . 最后得到最小生成树 T=<V, TE>,其中 TE 为最小生成树的边集。 cn ww 连通网用邻接矩 net 表示。若两个顶点之间不存在边,其权值为计算机内允许最大值;否则为 . w 对应边上的权值。
ww for (i=1; i<G.vexnum; ++i)
w t { // 选择其余 G.vexnum-1 个顶点
e k = minimum(closedge);
// 求出 T 的下一个结点:第 k 顶点
t .n 此时 closedge[k].lowcost =
ne ok MIN{ closedge[vi].lowcost | closedge[vi].lowcost>0, vi∈V-U }
et 的生成树;从不同的顶点出发,也可能得到不同的生成树。
t .n 设 G=(V, E)是一个带权连通图,E 中第 n 条边(U, V)。图 G 的一株生成树连接 V 中所有顶点的
ne ok 一株开放树。对于连通的带权图(连通网)G,其生成树也是带权的。生成树 T 各边的权值总和称
. o 为该树的权,记作:
oo c if (j!=k)
nb w. {
.c ww closedge[j].adjvex=u;
closedge[j].lowcost=G.arcs[k][j].adj;
ww }
w t }
ook.ne ※ 2 ※
.cnbook closedge[k].lowcost = 0;
// 初始,U={u}
ww { et // 新顶点并入 U 后重新选择最小边
n closedge[j] = { G.vexs[k], G.arcs[k][j].adj;}
et k. closedge[j].adjvex=G.vexs[k];
.n oo closedge[j].lowcost=G.arcs[k][j].adj;
. o printf(closedge[k].adjvex, G.vexs[k]); // 输出生成树的边
ok nb closedge[k].lowcost = 0;
// 第 k 顶点并入 U 集
.c for (j=0; j<G.vexnum; ++j)
w if (G.arcs[k][j].adj < closedge[j].lowcost)
e 现 在 证 明 最 小 生 成 树 满 足 上 述 性 质 。 为 方 便 说 明 , 先 作 约 定 : 权 最 小 的 边 称 为 轻 边 ( 即 权 重 最 t .n “轻”的边)。于是,MST 性质中所述的边(u, v)就可简称为轻边。 ne ok 用反证法证明 MST 性质:假设 G 中任何一棵 MST 都不含轻边(u, v)。则若 T 是 G 的一棵 MST, . o 则它不含此轻边。由于 T 是包含了 G 中所有顶点的连通图,所以 T 中必有一条从集合 U 中的顶点 u ok nb 到集合 V-U 中的顶点 v 的路径 P,且 P 上必有一条边(u', v')连接 U 集和 V-U 集,否则 u 和 v 不连通。 .c 当把轻边(u, v)加入树 T 时,该轻边和 P 必构成了一个回路。删去边(u', v')后回路亦消除,由此可 ww 得另一生成树 T'。T'和 T 的差别仅在于 T'用轻边(u, v)取代了 T 中权重可能更大的边(u', v')。因为 w(u, w v)≤w(u', v'),所以 w(T')=w(T)+w(u, v)-w(u', v')≤w(T),故 T'亦是 G 的 MST,它包含边(u, v),这与 et 假设矛盾。所以,MST 性质成立。
ok. nbo 1 最小生成树
bo .c 一个连通图的生成树是原图的极小连通子图,它包含原图中的所有顶点,且以尽可能少的边保
cn ww 持各顶点的连通。这意味着对于生成树来说,若去除它的一条边,就会使生成树变成非连通图;若
. w 给它增加一条边,就会形成图中的一个回路。另一方面,使用不同的遍历图的方法,可以得到不同
相关文档
最新文档