最小生成树问题的引入:

  对于一个无向图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)的更多相关文章

  1. 最小生成树 kruskal算法&prim算法

    (先更新到这,后面有时间再补,嘤嘤嘤) 今天给大家简单的讲一下最小生成树的问题吧!(ps:本人目前还比较菜,所以最小生成树最后的结果只能输出最小的权值,不能打印最小生成树的路径) 本Tianc在刚学的 ...

  2. 最小生成树算法prim and kruskal

    一.最小生成树定义:  从不同顶点出发或搜索次序不同,可得到不同的生成树  生成树的权:对连通网络来说,边附上权,生成树也带权,我们把生成树各边的权值总和称为生成树的权  最小代价生成树:在一个连通网 ...

  3. [数据结构]最小生成树算法Prim和Kruskal算法

    最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树.  例如,对于如上图G4所示的连通网可以有多棵权值总 ...

  4. 无向带权图的最小生成树算法——Prim及Kruskal算法思路

    边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...

  5. 最小生成树算法 prim kruskal两种算法实现 HDU-1863 畅通工程

    最小生成树 通俗解释:一个连通图,可将这个连通图删减任意条边,仍然保持连通图的状态并且所有边权值加起来的总和使其达到最小.这就是最小生成树 可以参考下图,便于理解 原来的图: 最小生成树(蓝色线): ...

  6. 最小生成树——Kruskal与Prim算法

    最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...

  7. 图论篇2——最小生成树算法(kurskal算法&prim算法)

    基本概念 树(Tree) 如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree) 无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树. 生成 ...

  8. 最小生成树MST算法(Prim、Kruskal)

    最小生成树MST(Minimum Spanning Tree) (1)概念 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边,所谓一个 ...

  9. ACM基础算法入门及题目列表

    对于刚进入大学的计算机类同学来说,算法与程序设计竞赛算是不错的选择,因为我们每天都在解决问题,锻炼着解决问题的能力. 这里以TZOJ题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...

随机推荐

  1. Vue/React如何优雅的一劳永逸的注册路由及组件

    原文链接: 本人掘金文章  假如图片看不清晰可前往掘金原文预览 官方文档: 组建注册 路由注册 未优化版: 在Vue官方文档 中,我们通过  Vue.component('MyComponentNam ...

  2. wepy_two

    2.代码高亮WebStorm/PhpStorm(其他工具参见:wepy官网代码高亮) (1)打开Settings,搜索Plugins,搜索Vue.js插件并安装. (2) 打开Settings,搜索F ...

  3. 树——populating-next-right-pointers-in-each-node(填充每个节点的next指针)

    问题: Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode ...

  4. ps:HSB色彩模式

    前面我们已经学习过了两大色彩模式RGB和CMYK.色彩模式有很多种,但这两种是最重要和最基础的.其余的色彩模式,实际上在显示的时候都需要转换为RGB,在打印或印刷(又称为输出)的时候都需要转为CMYK ...

  5. IncDec Sequence (差分)

    题目地址 这道题可以用来检测一下你是否学会了差分,或者你可以更加透彻的理解差分 我们把 \(cf[]\) (差分)数组拿出了,就可以发现这道题就是每次可以在 \(cf[]\)中 选两个数,一个+1,一 ...

  6. 解决安装mysql-connector-odbc-5.3.2 错误1918……不能加载安装或转换器库……的BUG

    还是在虚拟机Windows Server 2003上安装mysql-connector-odbc-5.3.2,装着装着就报错了,大致是“错误1918……不能加载安装或转换器库……”,问我Retry,I ...

  7. bui拍照上传、相册上传注意事项

    1.控制台输入 bui.currentPlatform  可查看工程项目基于什么平台  如:bingotouch 2.如果是 bingotouch , 在 index.js 或者其它配置的地方, 加上 ...

  8. 对webpack的初步研究7

    Configuration 您可能已经注意到很少有webpack配置看起来完全相同.这是因为webpack的配置文件是导出对象的JavaScript文件.然后,webpack根据其定义的属性处理此对象 ...

  9. DOSUtil

    package Testlink; import java.io.BufferedReader; import java.io.File; import java.io.IOException; im ...

  10. OpenCV笔记:pyrDown()函数和pryUp()函数的使用

    OpenCV实现了用于创建图像金字塔的两个函数pyrDown()和pryUp(). 图像金字塔是一种经典的图像多尺寸描述方法,它将降采样和平滑滤波结合在一起,对图像进行多尺度表示.图像金字塔由不同尺寸 ...