最小生成树基础算法(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题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...
随机推荐
- ES6——Promise
异步和同步 异步,操作之间没有关系,同时执行多个操作, 代码复杂 同步,同时只能做一件事,代码简单 Promise 对象 用同步的方式来书写异步代码 Promise 让异步操作写起来,像在写同步操作的 ...
- 2、Jmeter测试
一.测试流程 1.添加本次测试计划 (右键-->添加-->Threads(Users)-->线程组) 2.设置线程数 (所谓线程数就是并发用户数) 3.在线程组内添加请求(右键--& ...
- MemCache--01 解决session
目录 1. MemCache介绍 2.Session与Cookie介绍 3. 安装部署Nginx 4. 安装部署PHP 5. 安装Mariadb数据库 6. 部署网站(phpMyAdmin) 7. 部 ...
- 使用BaGet来管理内部Nuget包
有的时候,我们想要制作一些nuget包,供自己内部调用,不想公开出去,那么就需要一个能够集中管理nuget包的服务了,今天我来给大家介绍一款轻便好用的包管理服务-----BaGet 下载并部署BaGe ...
- python struct中的pack unpack
python struct中的pack unpack pytyon tuple元组 print struct.unpack("!ihb", buffer) 结果为7 //pyth ...
- eclipse的代码格式化的个性配置
1.安装jdk a. 到http://www.oracle.com/technetwork/java/javase/downloads/index.html 下载对应版本的jdk,安装到自己电脑上. ...
- case_when
select sname,score,case when score>=20 and score<30 then 20when score>=30 and score<40 t ...
- 英语单词composing
composing 来源——书籍Python.Crash.Course.2015.11 Using Individual Values from a List You can use individu ...
- Web开发中的服务器跳转与客户端跳转
两者比较如下: 跳转类型 客户端请求次数 服务端响应次数 URL变化 站外跳转 作用域 服务器跳转 1 1 无 否 pageContext.request.session.application 客 ...
- python 生成多维数组
在刷题时用到了数组,因为不提供三方库所以不能使用Numpy.想如何通过python列表模拟数组. 第一种方法 """ 生成n*m的初始值为0的矩阵 "" ...