贪心算法(图算法)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
最小生成树
Prim算法
练习:公路造价
【输入格式】 第一行两个数v(v<=200)和e分别代表城市数和边数,以 下e行,每行为两个顶点和它们之间的边权w(w<1000)。 【输出格式】 v-1行,每行为两个城市的序号,表明这两个城市间建一 条公路,再加该公路的造价。
最小生成树
Prim算法
最小生成树 #include <stdio.h>
并查集 const int MAXN = 100; /*结点数目上线*/
int pa[MAXN]; /*p[x]表示x的父结点*/ int rank[MAXN]; /*rank[x]是x的高度的一个
上界*/ 标准代码
/*创建一个单元集*/ void make_set(int x) {
练习:公路造价
【输入样例】
33 1 2 10 1 3 15 2 3 50
【输出样例】
1 2 10 1 3 15
最小生成树
Prim算法
练习:公路造价
代码 分析
(Prim.cpp)
最小生成树
思考
在某个城市里住着n个人,现在给定关于这n个人的m条 信息(即某2个人认识)。
假设所有认识的人一定属于同一个单位,请计算该城市 最多有多少单位?
最小生成树
最小生成树
最小生成树
Minimal Spanning Trees (MST) 任何只由G的边构成,并包含G的所有顶点
的树称为G的生成树(G连通)。加权无向图G 的生成树的代价是该生成树的所有边的代价 (权)的和,最小代价生成树是其所有生成 树中代价最小的生成树。
最小生成树
Prim算法:时间复杂度O(|V|2+|E|), O(|E|log|V|)
最小生成树
并查集
练习:无所不在的宗教
世界上宗教何其多。假设你对自己学校的学生总共有 多少种宗教信仰很感兴趣。学校有n个学生,但是你 不能直接问学生的信仰,不然他会感到很不舒服的。 有另外一个方法是问m对同学,是否信仰同一宗教。 根据这些数据,相信聪明的你是能够计算学校最多有 多少种宗教信仰的。
最小生成树
Prim算法
28
01
10 14 16
562
25 24 18 12
4 22 3
01
10 14 16
562
25
4
12
3
22
最小生成树
Prim算法
练习:公路造价
现有一张城市地图,图中的顶点为城市,无向边代表 两个城市间的连通关系,边上的权代表公路造价。在 分析了这张图后发现,任一对城市都是连通的。现在 要求用公路把所有城市联系起来,如何设计可使得工 程的总造价最少?
1
4
6
3 2
5
最小生成树
并查集
Union-Find Set 一种树型数据结构,用于处理一些不相交集合
(Disjoint Sets)的合并及查询问题 在使用中常常以森林来表示 可以把图中每个连通分量看成一个集合,该集合包含了
连通分量中的所有点,图的所有连通分量可以用若干个 不相交的集合来表示
Algorithms
贪心算法之图算法
刘 伟 (Sunny) weiliu_china126
内容
最小生成树 单源最短路径
Biblioteka Baidu 思考
若要将n个城市之间原 有的公路改造为高速公 路,这些城市之间原有 公路网如右图所示。如 何以最低的成本来构建 高速公路网,使得任意 两个城市之间都有高速 公路相连?
最小生成树
并查集
练习:无所不在的宗教
【输入格式】 可以输入多个测试用例(Case),每一个用例的第一行包含整 数n和m,n表示学生编号(1-n),在接下来的m行中,每一行 包含两个整数,对应信仰同一宗教的两名学生的编号,输入 结束行为n = m =0。 【输出格式】 输出每一个测试用例中包含的学生信仰的最大宗教数量。
沿着父结点指针一直找下去,直到找到树根为止
– 判断两个元素是否属于同一集合,只要判断它们所在集合的祖先 是否相同即可
– 合并两个集合,也是将一个集合的祖先作为另一个集合的祖先
union_set(x, y):利用find_set()找到其中两个集合的祖先,将 一个集合的祖先指向另一个集合的祖先
最小生成树
并查集
通过使用两种启发式策略(按秩合并和路径压缩)可以 达到渐进意义上最快的不相交集合数据结构
秩(Rank):表示结点高度的一个上界,树根的秩为0 union_set(x,y)时按秩合并,合并的时候将元素少的集合合并到
元素多的集合中,这样合并之后树的高度会相对较小,即每个 元素的秩相对较小 find_set(x)时路径压缩,当经过"递推"找到祖先结点后,"回溯" 的时候顺便将它的子孙结点都直接指向祖先,这样以后再次 find_set(x)时复杂度就变成O(1)了
x = find_set(x); //返回x的根结点 y = find_set(y); //返回y的根结点 if(rank[x] > rank[y])/*让rank比较高的作 为父结点*/
pa[y] = x; else {
pa[x] = y; if(rank[x] == rank[y])
rank[y]++; } }
最小生成树
并查集
将编号分别为1…N的N个对象划分为不相交集合,在每 个集合中,选择其中某个元素代表所在集合
常见操作: 合并两个集合 查找某元素属于哪个集合 判断两个元素是否属于同一个集合
最小生成树
并查集
三个基本操作
make_set(x):把每一个元素初始化为一个集合 find_set(x):查找一个元素所在的集合。在执行查找操作时,要
Kruskal算法:时间复杂度O(|E|log|E|) 算法的选择:
从图的稀疏程度考虑(稠密图Prim,稀疏图 Kruskal或Prim + Heap)
最小生成树
Prim算法
(1) 任意选定一点s,设集合S={s} (2) 从不在集合S的点中选出一个点j使得其与S
内的某点i的距离最短,则(i,j)就是生成树上的 一条边,同时将j点加入S (3) 转到(2)继续进行,直至所有点都己加入S 集合
pa[x] = x; rank[x] = 0; }
/*带路径压缩的查找*/ int find_set(int x) {
if(x != pa[x]) pa[x] = find_set(p[x]); //将所有结点的
父结点回溯为根结点 return pa[x];
}
/*按秩合并x,y所在的集合*/ void union_set(int x, int y) {