最小生成树

● 最小生成树的定义是给定一个无向图,如果它任意两个顶点都联通并且是一棵树,那么我们就称之为生成树(Spanning Tree)。如果是带权值的无向图,那么权值之和最小的生成树,我们就称之为最小生成树(MST, Minimum Spanning Tree)。

● 求最小生成树的算法有很多,可以用Prim, Kuskual, Boruvka, 甚至遗传算法。这里介绍较为基础的两种Prim算法和Kuskual算法。

Prim算法

​ 我们先建立两个点集,分别表示已经被加入到生成树中的点和还没有被加入到点集中的点分别记为集合V和集合T,一开始所有的点都在T集合中。

(1)我们将任意一个点从集合T置入集合V中。

(2)我们再在与集合V中的点连接的所有集合T的点中,找到一个点,使得这个点与集合V中的点的边最小,将这个点从集合T移动到集合V中。

(3)不断重复步骤(2),使得最终V包含所有图中的点。

P54-5.Prim算法_哔哩哔哩_bilibili

//sum使用引用可以把数值传出函数
void Prim(int n, float MGraph[][n], int v0, float& sum)
{
int lowCost[n], vSet[n];
int v, k, min;
for (int i = 0; i < n; i++)
{
lowCost[i] = MGraph[v0][i]; //将首个要访问的节点与其他节点的距离填入lowcost数组
vSet[i] = 0; //所有节点都没有访问过
}
v = v0; //当前节点设置为初节点
vSet[v] = 1; //初节点设置为访问过
sum = 0;
//已经访问过一个节点了,要遍历剩下的n-1个节点
for (int i = 0; i < n - 1; i++)
{
//要寻找到lowcost数组中的最小值
min = INF;
for (int j = 0; j < n; j++)
{
//lowcost最小值且没有遍历过的
if(vSet[j] == 0 && lowCost[j] < min)
{
min = lowCost[j];
k = j; //记录下最小值的序号
}
}
vSet[k] = 1; //把那个最小路径的节点记录已访问
v = k; //当前节点设置为最小路径节点
sum += min;
//更新lowcost数组
for (int j = 0; j < n; ++j)
{
//将未访问过的节点且是新节点下一个位置比之前lowcost小的节点更新
if (vSet[j] == 0 && MGraph[v][j] < lowCost[j])
lowCost[j] = MGraph[v][j];
}
}
}

P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 N,M,表示该图共有 N 个结点和 M 条无向边。

接下来 M 行每行包含三个整数 Xi,Yi,Zi,表示有一条长度为 Zi 的无向边连接结点 Xi,Yi,Zi

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

输入输出样例

输入

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出

7

输入

4 3
1 2 2
1 3 2
2 3 4

输出

orz

说明/提示

样例解释:

所以最小生成树的总边权为 2+2+3=7。

根据上述学习代码写出的题解:

#include <stdio.h>
int MGraph[5001][5001];
int vSet[5001];
int lowCost[5001];
int N;
#define INF 10000;
int Prim(int v0)
{
int v, k=0, min;
for (int i = 1; i <= N; i++)
{
lowCost[i] = MGraph[v0][i];
vSet[i] = 0;
}
v = v0;
vSet[v] = 1;
int sum = 0;
for (int i = 2; i <= N; i++)
{
min = INF;
for (int j = 1; j <= N; j++)
{
if (vSet[j] == 0 && lowCost[j] < min)
{
min = lowCost[j];
k = j;
}
}
vSet[k] = 1;
v = k;
sum += min;
for (int j = 1; j <= N; ++j)
{
if (vSet[j] == 0 && MGraph[v][j] < lowCost[j])
lowCost[j] = MGraph[v][j];
}
}
for (int i = 1; i <= N; i++)
if (vSet[i] == 0) return -1;
return sum;
} int main(void) {
int i, j, k, dist;
int M;
scanf("%d %d", &N, &M);
for (i = 1; i <= N; i++) {
for (j = 1; j <= N; j++) {
MGraph[i][j] = INF;
if (i == j) MGraph[i][j] = 0;
}
}
for (i = 1; i <= M; i++) {
scanf("%d %d %d", &j, &k, &dist);
MGraph[j][k] = dist;
MGraph[k][j] = dist;
}
int res = Prim(1);
if (res == -1) printf("orz");
else printf("%d", res);
return 0;
}

课上给的题解,照着前面的思路改了变量名加了注释。

#include <stdio.h>
int MGraph[5001][5001];
int vSet[5001];
int lowCost[5001];
int N;
void Prim(int v0)
{
int i, j, k, cnt;
int mindis, v;
mindis = 0, v = v0;
for (i = 1; i <= N; i++)
{
vSet[i] = 0; //vSet置0
lowCost[i] = -1; //lowCost置-1
}
lowCost[v] = 0; //初始节点的lowcost置0
//开始遍历剩下的n-1个节点
for (cnt = 1; cnt < N && v; cnt++) {
vSet[v] = 1;
j = v, v = 0, mindis = 1000000001;
//遍历每个未访问过的节点更新lowcost数组
for (i = 1; i <= N; i++)
{
if (vSet[i]==0)
{
if (MGraph[j][i] != -1)
{
if (lowCost[i] == -1 || MGraph[j][i] < lowCost[i])
lowCost[i] = MGraph[j][i];
}
if (lowCost[i] != -1 && mindis > lowCost[i])
{
mindis = lowCost[i];
v = i;
}
}
}
}
if (cnt != N) printf("orz\n");
else {
long long ans = 0;
//累加lowcost数组即可得到最短路径
for (i = 1; i <= N; i++)
ans += lowCost[i];
printf("%lld\n", ans);
}
return;
} int main(void) {
int i, j, k, dist;
int M;
scanf("%d %d", &N, &M);
//将初始邻接矩阵置-1
for (i = 1; i <= N; i++) {
for (j = 1; j <= N; j++) {
MGraph[i][j] = -1;
if (i == j) {
MGraph[i][j] = 0;
}
}
}
for (i = 1; i <= M; i++) {
scanf("%d %d %d", &j, &k, &dist);
if (MGraph[j][k] == -1 || MGraph[j][k] > dist) {
MGraph[j][k] = dist;
MGraph[k][j] = dist;
}
}
Prim(1);
return 0;
}

【ACM程序设计】最小生成树 Prim算法的更多相关文章

  1. 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。

    //归并排序递归方法实现 #include <iostream> #include <cstdio> using namespace std; #define maxn 100 ...

  2. 最小生成树Prim算法(邻接矩阵和邻接表)

    最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...

  3. 最小生成树—prim算法

    最小生成树prim算法实现 所谓生成树,就是n个点之间连成n-1条边的图形.而最小生成树,就是权值(两点间直线的值)之和的最小值. 首先,要用二维数组记录点和权值.如上图所示无向图: int map[ ...

  4. Highways POJ-1751 最小生成树 Prim算法

    Highways POJ-1751 最小生成树 Prim算法 题意 有一个N个城市M条路的无向图,给你N个城市的坐标,然后现在该无向图已经有M条边了,问你还需要添加总长为多少的边能使得该无向图连通.输 ...

  5. SWUST OJ 1075 求最小生成树(Prim算法)

    求最小生成树(Prim算法) 我对提示代码做了简要分析,提示代码大致写了以下几个内容 给了几个基础的工具,邻接表记录图的一个的结构体,记录Prim算法中最近的边的结构体,记录目标边的结构体(始末点,值 ...

  6. 图论算法(五)最小生成树Prim算法

    最小生成树\(Prim\)算法 我们通常求最小生成树有两种常见的算法--\(Prim\)和\(Kruskal\)算法,今天先总结最小生成树概念和比较简单的\(Prim\)算法 Part 1:最小生成树 ...

  7. 最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析

    最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析 最小生成树,老生常谈了,生活中也总会有各种各样的问题,在这里,我来带你一起分析一下这个算法的思路与实现的方式吧~~ 在考研中呢 ...

  8. HDU1102 最小生成树prim算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 题意:给出任意两个城市之间建一条路的时间,给出哪些城市之间已经建好,问最少还要多少时间使所有的城 ...

  9. 最小生成树——prim算法

    prim算法是选取任意一个顶点作为树的一个节点,然后贪心的选取离这棵树最近的点,直到连上所有的点并且不够成环,它的时间复杂度为o(v^2) #include<iostream>#inclu ...

随机推荐

  1. 说说has a与is a的区别?

    is a是典型的"一般到特殊"的关系,也就是典型的继承关系.例如Apple is a Fruit.那么Apple是一种特殊的Fruit,也就是说Apple继承了Fruit. has ...

  2. 什么是memecache?redis 和 memecache 有什么区别?

    什么是memecache? memcached是一套分布式的高速缓存系统,与redis相似.一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度.提高可扩展性.为了 ...

  3. js技术之拖动table标签

    一.js技术之拖动table标签 起因:前几天公司,突然安排一个任务 任务描述:要求尺码table列表要像Excel表中一样可以直接移动整行尺码到任意行位置 技术点:采用ui的sortable技术来h ...

  4. 如何在 Microsoft word中插入代码

    一.工具 方法1.打开这个网页PlanetB; 方法2.或者谷歌搜索syntax highlight code in word documents,检索结果的第一个.如下图: PS. 方法1和2打开的 ...

  5. Amaze UI 模版中心上线丨十几款高质量优秀模版免费提供!

    Amaze UI模版中心终于上线了,目前汇聚了包含企业门户.新闻资讯.管理后台等多个领域的模版,全都可以免费下载. Amaze UI模版中心后续还会增加更多的模版以及领域,请各位持续关注. 模版中心的 ...

  6. 基于React的仿QQ音乐(移动端)

    前言 由于这段时间工作上也是挺忙的,就没有时间去写这个项目,中间一直都是写写停停,进度也是非常慢的.正好前几天都还比较空,就赶紧抓着空闲时间去写这个项目,最后紧赶慢赶地完成了.本项目采用了React的 ...

  7. java中请给一个Abstract类实现接口的实例!

    2.Abstract类实现接口 马克-to-win:如果实现某接口的类是abstract类,则它可以不实现该接口所有的方法.但其非abstract的子类中必须拥有所有抽象方法的实在的方法体:(当然它a ...

  8. CSS样式写在JSP代码中的几种方法

    1.行内样式. 可以直接把css代码写在现有的HTML标签元素的开始标签里面,并且css样式代码要写在style=" "双引号中才可以, 如: <p style=" ...

  9. ES6(Promise)等一个函数执行完后再执行另一个函数

    function text1(){ return new Promise((resolve, reject) => { setTimeout(function () { resolve(cons ...

  10. 拼写检查-c++

    [问题描述] 作为一个新的拼写检查程序开发团队的成员,您将编写一个模块,用已知的所有形式正确的词典来检查给定单词的正确性.        如果字典中没有这个词,那么可以用下列操作中的一个来替换正确的单 ...