最小生成树基础算法(Prim + Krustal)
最小生成树问题的引入:
对于一个无向图G(V, E),需要用图中的n - 1条边连接图中的n个顶点并且不产生回路所产生的树就叫做生成树,其中权值总和最小的就是最小生成树。
如何求解最小生成树问题:
譬如给定一个无向图G(V, E),要如何求出这个图的一个最小生成树呢?
下面我们先给出这个问题的一个总的解决方法:
我们先假设集合A为满足A为图G的最小生成树的边的集合。
条件P:A为G的最小生成树的子集。
起初 : 我们设定A为空集,显然此时集合A满足条件P。
添加边:每次我们找到一条边(u, v),使得A U { (u, v) } 这个集合依然满足条件P,我们找到的这条边(u, v)被称为集合A的安全边。
以上就是最小生成树的求解过程,我们可以很容易看出这个求解操作中的关键部分就是如何找出符合条件的安全边。那么下面我们先给出求解最小生成树问题的伪代码。
GENERIC-MST(G, w)
A <- NULL Set
while(A does not form a spanning tree)
find an edge(u, v) that is safe for A
A = A U {(u, v)}
return A
Kruskal:
Kruskal算法思想:任意时刻的中间结果是一个森林。初始n个点的集合,每次选择权重最小且不会产生圈的边加入集合A,合并两个森林。为了方便检测环和加边,需要借助并查集。
Kruskal加边操作:贪心思想,每次择最优,保证不成环即可。
Kruskal具体操作:
初始化:每个顶点独立成为一个森林。
加边:在所有边中选择一条权重最小的边用来连接两个森林,所选择的这条边需要保证合并森林不会生成环。
下面给出Kruskal算法的伪代码:
MST-KRUSKAL(G, w)
A <- NULL Set
for each vertex v
Make_Set(v)
sort the edges of G.E into nondecreasing order by weight w
for each edge(u, v) taken in nondecreasing order by weight
if(Find(u) != Find(v))
A = A U {(u, v)}
Union(u, v)
return A
Kruskal算法参考代码:
typedef pair<int, int> pii;
const int maxn = + , maxe = + ;
int n, e;//全局变量,图中的点和边的数目
struct Edge {
int x, y, cost;
} edge[maxe];//全局变量,edge[i]表示第i条边的信息
int ans = ;//表示为最小生成树的边权和
int num = ;//表示所求出的边的数量
pii spanning[maxn];//存储最小生成树的每条边
int head[maxn], Rank[maxn]; void Make_Set(int n) {
for(int i = ; i <= n; i ++) {
Rank[i] = ;
head[i] = i;
}
} int Find(int u) {
if(u == head[u]) return u;
else return head[u] = Find(head[u]);
} void Union(int u, int v) {
int hu = Find(u), hv = Find(v);
if(Rank[hu] > Rank[hv])
head[hv] = hu;
else {
head[hu] = hv;
if(Rank[hu] == Rank[hv]) Rank[hv] += ;
}
} bool Is_same(int u, int v) {
return Find(u) == Find(v);
} bool cmp(Edge a, Edge b) {
return a.cost < b.cost;
} int Kruskal() {
sort(edge + , edge + e + , cmp);
int cnt = n;
Make_Set(n);
for(int i = ; i <= e; i ++) {
if(!Is_same(edge[i].x, edge[i].y)) {
Union(edge[i].x, edge[i].y);
ans += edge[i].cost;
spanning[++num].first = edge[i].x;
spanning[num].second = edge[i].y;
if(cnt == ) break;//若只剩下一个连通块即最小生成树已经生成,则退出
}
}
return ans;
}
Prim:
Prim算法思想:任意时刻的中间结果都是一颗最小生成树的子树。从指定的一个点开始,每次都花最少的代价,用一条边把一个不在树中的结点加进来。为了方便选择离树最近的点,需要借助堆。
Prim加边操作:贪心策略,每次选择一条边(u, v)保证u已经是最小生成树子树内的结点,v是最小生成树子树内的所有结点u出发的边的tail结点,每次选择保证边(u, v)的权重最小。
Prim算法具体操作:
初始化:将初始点标记。
加边:每次找一条最短的两端分别为标记和未标记的边加入最小生成树子树并把未标记的点标记上。即每次加入一条安全边,每次扩展一个点由未标记为变已标记,
直至扩展至n个点。
下面给出Prim算法的伪代码:
MST-PRIM(G, w, source)
for each vertex u
u:key <- Infinite //表示距离结点u最近的结点到u的距离
u.head <- NULL//表示距离结点u最近的结点的编号
source:key <-
Q <- G.Vertex // the source vertex
while(Q != NULLSet)
u <- EXTRACT-MIN(Q)//Find and Delete
for each v belong to G.Adj[u]
if(v belong to Q and w(u, v) < v.key)
v.head <- u;
v.key <- w(u, v);
Q <- v
Prim算法实现代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <vector>
using namespace std; typedef pair<int, int> pii;
const int maxn = + , maxe = + , INF = 0x3f3f3f3f;
struct Edge {
int to, cost;
friend bool operator < (const Edge &a, const Edge&b) {
return a.cost > b.cost;
}
};
vector<Edge> edge[maxe];
int n, e, ans, dist[maxn];
bool vis[maxn]; void addedge(int u, int v, int w) {
edge[u].push_back({v, w});
} void MST_Prim(int source) {
memset(vis, false, sizeof vis);
for(int i = ; i <= n; i ++) dist[i] = INF;
dist[source] = ans = ;
priority_queue <Edge> Q;
Q.push({source, dist[source]});
while(!Q.empty()) {
Edge u = Q.top();
Q.pop();
if(vis[u.to]) continue;
vis[u.to] = true;
ans += dist[u.to];
for(int i = ; i < edge[u.to].size(); i ++) {
Edge e = edge[u.to][i];
if(dist[e.to] > e.cost) {
dist[e.to] = e.cost;
Q.push({e.to, dist[e.to]});
}
}
}
} int main() {
int x, y, w;
scanf("%d", &n);
for(int i = ; i <= n; i ++) {
scanf("%d %d %d", &x, &y, &w);
addedge(x, y, w);
addedge(y, x, w);
}
MST_Prim();
for(int i = ; i <= n; i++) edge[i].clear();//被这个坑了一天,一定要记住全局变量要清空
return ;
}
最小生成树基础算法(Prim + Krustal)的更多相关文章
- 最小生成树 kruskal算法&prim算法
(先更新到这,后面有时间再补,嘤嘤嘤) 今天给大家简单的讲一下最小生成树的问题吧!(ps:本人目前还比较菜,所以最小生成树最后的结果只能输出最小的权值,不能打印最小生成树的路径) 本Tianc在刚学的 ...
- 最小生成树算法prim and kruskal
一.最小生成树定义: 从不同顶点出发或搜索次序不同,可得到不同的生成树 生成树的权:对连通网络来说,边附上权,生成树也带权,我们把生成树各边的权值总和称为生成树的权 最小代价生成树:在一个连通网 ...
- [数据结构]最小生成树算法Prim和Kruskal算法
最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树. 例如,对于如上图G4所示的连通网可以有多棵权值总 ...
- 无向带权图的最小生成树算法——Prim及Kruskal算法思路
边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...
- 最小生成树算法 prim kruskal两种算法实现 HDU-1863 畅通工程
最小生成树 通俗解释:一个连通图,可将这个连通图删减任意条边,仍然保持连通图的状态并且所有边权值加起来的总和使其达到最小.这就是最小生成树 可以参考下图,便于理解 原来的图: 最小生成树(蓝色线): ...
- 最小生成树——Kruskal与Prim算法
最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...
- 图论篇2——最小生成树算法(kurskal算法&prim算法)
基本概念 树(Tree) 如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree) 无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树. 生成 ...
- 最小生成树MST算法(Prim、Kruskal)
最小生成树MST(Minimum Spanning Tree) (1)概念 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边,所谓一个 ...
- ACM基础算法入门及题目列表
对于刚进入大学的计算机类同学来说,算法与程序设计竞赛算是不错的选择,因为我们每天都在解决问题,锻炼着解决问题的能力. 这里以TZOJ题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...
随机推荐
- python学习笔记(11):文件的访问与函数式编程
一.文本文件读写的三种方法 1.直接读入 file1 = open('E:/hello/hello.txt') file2 = open('output.txt','w') #w是可写的文件 whil ...
- meter标签度量衡如何改变颜色
此文章为转载,目的为了方便整理学习笔记. 在meter中要想改变颜色,需要用到五个值,分别是:min(最小值).max(最大值).low.high.value和optimum,其中前四个值会把整个进度 ...
- Sql Server 出现此数据库没有有效所有者问题
在新建数据库或附加数据库后,想添加关系表,结果出现下面的错误: 此数据库没有有效所有者,因此无法安装数据库关系图支持对象.若要继续,请首先使用“数据库属性”对话框的“文件”页或ALTER AUTHO ...
- CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirrors.ustc.edu.cn/anaconda/pkg
conda安装时一直报错,换源什么的都不好使,折腾了半天,直到看到https://blog.csdn.net/u013383596/article/details/87718472 将https改为h ...
- Sass:@at-root
@at-root 从字面上解释就是跳出根元素.当你选择器嵌套多层之后,想让某个选择器跳出,此时就可以使用 @at-root.来看一个简单的示例: .a { color: red; .b { color ...
- JS基础入门篇(七)—运算符
1.算术运算符 1.算术运算符 算术运算符:+ ,- ,* ,/ ,%(取余) ,++ ,-- . 重点:++和--前置和后置的区别. 1.1 前置 ++ 和 后置 ++ 前置++:先自增值,再使用值 ...
- springboot-启动一段时间图片不能上传
问题:[B2B]后台服务.PC服务.APP服务.仓储服务,启动一段时间图片不能上传. 原因:/tmp下以tomcat开头的目录被清理了. 处理方案:1.找到涉及服务器 注:后台服务.PC服务.APP服 ...
- toj 4063 单词(AC自动机)
题目: 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成的. 但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入 第一行一个整数N,表示有N个单词.接 ...
- windows命令整理
本文只是作为知识整理,尽可能的收集一些常用的内网指令.本人原伸手党一枚,希望这些内容对新人有用,大牛可自行忽略. 0x00 内网信息收集 一.单机基础信息收集 如果是获得第一台初始主机的权限的话,我们 ...
- hdu 4845 : 拯救大兵瑞恩 (bfs+状态压缩)
题目链接 #include<bits/stdc++.h> using namespace std; typedef long long LL; int n,m,p,s,k; ,,,-}; ...