最小生成树基础算法(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 ...
- MySQL语句之数据的增删改查
1.插入记录insert语法:INSERT INTO tablename (field1,field2,……fieldn) VALUES(value1,value2,……valuesn); 也可以一次 ...
- Sql Server 2008安装时提示重启计算机失败解决办法
在键盘上按下组合键[Win]+[R],调出运行窗口. 在窗口中输入“regedit”,点击确定,打开注册表管理界面. 在注册表左侧目录栏中找到如下位置:“HKEY_LOCAL_MACHINE\ ...
- python os 常用命令
转载:http://www.cnblogs.com/kaituorensheng/archive/2013/03/18/2965766.html python编程时,经常和文件.目录打交道,这是就离不 ...
- Docker 基础学习(一)
Docker官网:https://docker.com/ 中文翻译非常好的学习地址:http://dockerpool.com/static/books/docker_practice/index.h ...
- kafka参数设置
一.broker参数 broker.id:kafka集群的唯一标识. log.dirs:kafka存储消息日志的目录,多个用逗号隔开,需要保证指定的目录有充足的磁盘空间. zookeeper.conn ...
- bzoj3252 攻略 贪心+dfs序+线段树
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3252 题解 有一个非常显然的贪心思路:每次选择目前走到那儿能够获得的新权值最大的点. 证明的话 ...
- 网络安全意识有多重要?SamSam勒索软件敲诈了近600万美元
近年来,对于网络犯罪分子来说,勒索软件已成为数百万美元的黑市业务,SamSam就是一个很好的例子. 中国信息安全新研究显示,自2015年12月以来,SamSam勒索软件从受害者手中敲诈了近600万美元 ...
- springboot-启动一段时间图片不能上传
问题:[B2B]后台服务.PC服务.APP服务.仓储服务,启动一段时间图片不能上传. 原因:/tmp下以tomcat开头的目录被清理了. 处理方案:1.找到涉及服务器 注:后台服务.PC服务.APP服 ...
- window.onload()和$(document).ready的区别( $(document).ready == $(function(){ }) )
首先$(function(){}) 和 $(document).ready(function(){}) 是一个方法,$(function(){})为简写(用的多) $(document).ready和 ...