最小生成树问题的引入:

  对于一个无向图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. $_ENV输出为null的原因及解决办法

    有些朋友输出$_ENV是空的,可能原因是php.ini的variables_order值为"GPCS",也就是说系统在定义PHP预定义变量时的顺序是GET,POST,COOKIES ...

  2. linux测试 Sersync 是否正常

    [root@SERSYNC web]# for i in {1..10000};do echo 123456 > /data/web/$i &>/dev/null;do ne [r ...

  3. TensorFlow——实现线性回归算法

    import tensorflow as tf import numpy as np import matplotlib.pyplot as plt #使用numpy生成200个随机点 x_data= ...

  4. windows重装系统之前与之后进行的操作

    1.原系统的备份 避免重装遇到故障无法恢复,给自己留一条后路. 重装系统之前首先进行一次系统备份,我使用的备份软件是dism++,这个软件还可以完成其他的诸如空间回收.系统优化等操作: 软件地址:ht ...

  5. [POI2006]ORK-Ploughing(贪心,枚举)

    [POI2006]ORK-Ploughing 题目描述 Byteasar, the farmer, wants to plough his rectangular field. He can begi ...

  6. Java EE的优越性主要表现在哪些方面

    J2 EE的优越性主要表现在哪些方面 J2EE基于JAVA 技术,与平台无关. J2EE拥有开放标准,许多大型公司实现了对该规范支持的应用服务器.如BEA ,IBM,ORACLE等. J2EE提供相当 ...

  7. 对promise的研究1

    通过看阮一峰老师的文章写出来的特此注明 1.Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.它由社区最早提出和实现,ES6 将其 ...

  8. 04 全局配置,java 编意默认版本,1.6.修改配置

    https://www.cnblogs.com/liu-s/p/5371289.html <!-- 修改Intellij Idea 创建maven项目默认Java编译版本 --> < ...

  9. MySql不区分大小写。

    解决方案: 1:给相关字段添加上让其区分大小写. alter table 表名 modify column 字段名 varchar(100) binary character set utf8

  10. 简述php标记符有哪些

    <?php ?> 是PHP的解析符(长标记),所有需要运行的代码都要放到解析符中. 1 2 3 <?php echo "hello world"; ?> 短 ...