当前位置:文档之家› 第3章算法设计与分析基础

第3章算法设计与分析基础

b
3 4 1 4
c
6 5
a
6
5
f
2
d
8
e
Return Et
9.1 Prim算法
Prim(V,E) Vt={v0} Et=Φ for i=1 to |V|-1 do
在<v,u>(v∈Vt, u∈ V-Vt)中求 权重最小的边e*=<v*,u*> Vt = Vt∪{ u*} Et = Et∪{ e*}
b
3 4 1 4
c
6 5
a
6
5
f
2
d
8
e
Return Et
9.1 Prim算法
Prim(V,E) Vt={v0} Et=Φ for i=1 to |V|-1 do
在<v,u>(v∈Vt, u∈ V-Vt)中求 权重最小的边e*=<v*,u*> Vt = Vt∪{ u*} Et = Et∪{ e*}
单源最短路径问题
给定带权有向图G =(V,E),其中每条边的权是非 负实数。
给定V中的一个顶点,称为源。
计算从源到所有其他各顶点的最短路径长度。这 里路径的长度是指路径上各边权之和。
9.3 Dijkstra算法
对下图中的有向图,如何考虑用贪心法获得 从源顶点1到其他顶点间最短路径
9.3 Dijkstra算法
如何贪婪?
首先,求出起点出发最近点的距离;然后,第二 近,依次类推
允许通过其它点为中间节点
9.3 Dijkstra算法
设置顶点集合S,一个顶点属于集合S当且仅 当从源到该顶点的最短路径长度已知。 用贪心方法贪心选择来扩充这个集合。
初始时,S中仅含有源。 每次从V-S中取出具有最短特殊路长度的顶点u*, 将u*添加到S中,同时对数组dist作如下修改: dist(u0, u)=min{dist(u0, u), dist(u0, u*)+dist(u*, u)} 一旦S包含了所有V中顶点,dist就记录了从源到所 有其他顶点之间的最短路径长度。
第九章 贪心法
什么是贪心?
逐步给出解的各部分, 在每一步“贪婪地” 选择最好的部分解,但不顾 及这样选择对整体的影响, 因此一般地得到的不是最好的解。
每一步要满足的条件
可行 局部最优
不可取消
第九章 贪心法
9.1 Prim算法 9.2 kruskal算法 9.3 Dijkstra算法 9.4 哈夫曼树
9.3 Dijkstra算法
Dijkstra算法的迭代过程:
迭代
初始 1 2 3 4
S
{1} {1,2} {1,2,4} {1,2,4,3} {1,2,4,3,5}
u
2 4 3 5
dist[2] dist[3] dist[ 4]
10 10 10 10 10 maxint 60 50 50 50 30 30 30 30 30
b
3 4 1 4
c
6 5
a
6
5
f
2
d
8
e
Return Et
9.1 Prim算法
Prim(V,E) Vt={v0} Et=Φ for i=1 to |V|-1 do
在<v,u>(v∈Vt, u∈ V-Vt)中求 权重最小的边e*=<v*,u*> Vt = Vt∪{ u*} Et = Et∪{ e*}
最终时,只有一颗树 每次迭代中新边的加入等价于从图中找到一条边,当顶点分 别属于不同的树时,选取该边,使两棵树变为一棵更大的 树。
通过union-find(并查)算法实现,对两个顶点是否属 于同棵树(集合)的考察 最终时间复杂度约为O(|E|log|E|)
9.3 Dijkstra算法
确定如何将待解问题分解成若干步骤
Prim算法:最小生成树的子树
(3)确定贪心策略
扩大部分解的方法,一般涉及极值选择
(4)确定候选集
明确贪心的选择范围
(5)调整候选集 (6)正确性证明
贪心法总结
逐步给出解的各部分,在每一步“贪婪 地” 选择最好的部分解,但不顾及这样 选择对整体的影响。
较长比特串给不常用字符
前缀码:所有的比特串都不是另一个字符比特串 的前缀 考虑用树的形式
9.4 哈夫曼编码
哈夫曼编码算法用字符在文件中出现的频率 表来建立一个用0,1串表示各字符的最优表 示方式。
考虑将字符和二叉树的叶子联系起来形成前 缀码
关键字位于叶子节点,且关键字具有出现频率 使对这些关键字编码后的平均长度最小
9.1 Prim算法
设G =(V,E)是无向连通带权图,E中每条边(v,w) 的权重为c[v][w]。 如果G的子图G’是一棵包含G的所有顶点的树, 则称G’为G的生成树。 在G的所有生成树中,所有边的权重总和最小 的生成树称为G的最小生成树。
9.1 Prim算法
图的最小生成树在实际中有广泛应用。 例如,在设计通信网络时,用图的顶点表示 城市,用边(v,w)的权c[v][w]表示建立城市v 和城市w之间的通信线路所需的费用,则最小 生成树就给出了建立通信网络的最经济的方 案。
9.1 Prim算法-基本思想
设G=(V,E)是连通带权图,V={1,2,…,n}。如 何用贪心呢? 给定一个起始点,如何贪心?
选择与这个起始点最近的点加入
有了n个点,后续如何贪心?
选择与这n个点距离最小的点加入
9.1 Prim算法-基本思想
首先置S={1} 然后,只要S是V的真子集,就作如下的贪心 选择:
b
3 4 1 4
c
6 5
a
6
5
f
2
d
8
e
Return Et
9.1 Prim算法
Prim(V,E) Vt={v0} Et=Φ for i=1 to |V|-1 do
在<v,u>(v∈Vt, u∈ V-Vt)中求 权重最小的边e*=<v*,u*> Vt = Vt∪{ u*} Et = Et∪{ e*}
9.4 哈夫曼编码
已知字母A、B、C、D、E、F出现的频率如 下:A——30%,B——25%,C——20% D——10%,E——10%,F—— 5%
100 45
55
25 15
A 30
B 25
C 20
D 10
E 10
F 5
贪心法要素总结(参考)
(1)明确目标函数和约束条件 (2)制定部分解结构。
dist[ 5]
100 100 90 60 60
9.3 Dijkstra算法
时间复杂度
图-权重矩阵,优先队列-数组 Θ(|V|2) 图-邻接链表,优先队列-最小堆
Θ(|E|log|V|)
9.4 哈夫曼编码
编码
文本中的字符赋予一串比特位 定长编码 变长编码:
较短的比特串给常用字符
每一步满足“可行,局部最优,不可取 消”
9.2 kruskal算法
b
3 4
5
1 4
c
6 5
a
6
f
2
d
8
e
9.2 kruskal算法
b
3 4
5
1 4
c
6 5
a
6
f
2
d
8
e
9.2 kruskal算法
b
3 4
5
1 4
c
6 5
a
6
f
2
d
8
e
9.2 kruskal算法
b
3 4
5
1 4
c
6 5
a
6
f
2
d
8
e
9.2 kruskal算法
b
3 4
b
3 4 1 4
c
6 5
a
6
5
f
2
d
8
e
Return Et
Prim算法的效率
最复杂部分
在<v,u>(v∈Vt, u∈ V-Vt)中求权重最小的边 e*=<v*,u*>
取决于表示图的数据结构,以及表示V-S的优 先队列的数据结构
图--权重矩阵;优先队列—无序数组
运行时间属于Θ(|V|2)
如何贪心?
让概率小的先编码(先编码的,码长长)
9.4 哈夫曼编码
编码过程:
初始化n个字符单节点的树,每个字符具有概率, 记为权重
重复下面的步骤直到剩下一棵单独的树。
找到两个树权重最小,把他们作为新树中的左右子树。 并把其权重之和作为新的权重记录在新树的根中。
左子树边标0,右子树边标1,从根节点到叶子节 点的路径就是哈夫曼编码
图—邻接链表;优先队列—最小堆
运行时间O(|E|log|V|)
9.2 kruskal算法
Prim算法每次是节点扩增,是否可以用边扩 增的方法?
Kruskal
在边扩增时,如何体现贪心?
第一条边的选择,如何贪心?
选择权重最小的边加入
已经有了n个条边,后续如何贪心?
选择与权重最小的边加入,同时满足不生成环
选取满足条件i∈S,j∈V-S,且c[i][j]最小的边 将顶点j添加到S中。
这个过程一直进行到S=V时为止。
在这个过程中选取到的所有边恰好构成G的一 棵最小生成树。
9.1 Prim算法
Prim(V,E) Vt={v0} Et=Φ for i=1 to |V|-1 do
在<v,u>(v∈Vt, u∈ V-Vt)中求 权重最小的边e*=<v*,u*> Vt = Vt∪{ u*} Et = Et∪{ e*}
相关主题