【ACM程序设计】最小生成树 Prim算法
最小生成树
● 最小生成树的定义是给定一个无向图,如果它任意两个顶点都联通并且是一棵树,那么我们就称之为生成树(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包含所有图中的点。


//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算法的更多相关文章
- 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。
//归并排序递归方法实现 #include <iostream> #include <cstdio> using namespace std; #define maxn 100 ...
- 最小生成树Prim算法(邻接矩阵和邻接表)
最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...
- 最小生成树—prim算法
最小生成树prim算法实现 所谓生成树,就是n个点之间连成n-1条边的图形.而最小生成树,就是权值(两点间直线的值)之和的最小值. 首先,要用二维数组记录点和权值.如上图所示无向图: int map[ ...
- Highways POJ-1751 最小生成树 Prim算法
Highways POJ-1751 最小生成树 Prim算法 题意 有一个N个城市M条路的无向图,给你N个城市的坐标,然后现在该无向图已经有M条边了,问你还需要添加总长为多少的边能使得该无向图连通.输 ...
- SWUST OJ 1075 求最小生成树(Prim算法)
求最小生成树(Prim算法) 我对提示代码做了简要分析,提示代码大致写了以下几个内容 给了几个基础的工具,邻接表记录图的一个的结构体,记录Prim算法中最近的边的结构体,记录目标边的结构体(始末点,值 ...
- 图论算法(五)最小生成树Prim算法
最小生成树\(Prim\)算法 我们通常求最小生成树有两种常见的算法--\(Prim\)和\(Kruskal\)算法,今天先总结最小生成树概念和比较简单的\(Prim\)算法 Part 1:最小生成树 ...
- 最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析
最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析 最小生成树,老生常谈了,生活中也总会有各种各样的问题,在这里,我来带你一起分析一下这个算法的思路与实现的方式吧~~ 在考研中呢 ...
- HDU1102 最小生成树prim算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102 题意:给出任意两个城市之间建一条路的时间,给出哪些城市之间已经建好,问最少还要多少时间使所有的城 ...
- 最小生成树——prim算法
prim算法是选取任意一个顶点作为树的一个节点,然后贪心的选取离这棵树最近的点,直到连上所有的点并且不够成环,它的时间复杂度为o(v^2) #include<iostream>#inclu ...
随机推荐
- 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法?
通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间:而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集 ...
- jQuery--选择器案例实战
1.案例需求 jquery最基础的选择器部分已经基本结束,来一个简单案例总结回顾下学的东西. 案例需求: 用一个按钮控制元素的显示与隐藏,页面如下,从第五个开始,不要最后一个,控制他们的显示和隐藏. ...
- git-learningmeiy
什么是版本控制-版本迭代: 版本控制(Revision control)是一种在开发的过程中用于管理我们对文件.目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术. ...
- Spring AOP and AspectJ AOP 有什么区别?
Spring AOP 基于动态代理方式实现:AspectJ 基于静态代理方式实现.Spring AOP 仅支持方法级别的 PointCut:提供了完全的 AOP 支持,它还支持属性级别的 PointC ...
- vulnhub 靶机 Kioptrix Level 1渗透笔记
靶机下载地址:https://www.vulnhub.com/entry/kioptrix-level-1-1,22/ kali ip 信息收集 先使用nmap收集目标的ip地址 nmap -sP 1 ...
- css流程图、步骤图,流程线与环节分别实现,支持单环节、多环节情况。scss生成CSS
适用于分步骤操作的页面导航图 实现结果如下 上图对应下述代码,稍作修改可以生成下图.css代码如下: @charset "UTF-8"; /**单列宽度 单行高度 列数 行数*/ ...
- css3 nth-child选择器
css3 nth-child选择器 css3的nth-child选择器,乍看起来很简单,其实不是那么容易. 简单用法 p:nth-child(n) // 选择属于其父元素的第n个子元素的每个 < ...
- 微信小程序开发:python+sanic 实现小程序登录注册
开发微信小程序时,接入小程序的授权登录可以快速实现用户注册登录的步骤,是快速建立用户体系的重要一步.这篇文章将介绍 python + sanic + 微信小程序实现用户快速注册登录全栈方案. 微信小程 ...
- 安卓性能测试之 adb shell 常用命令
pm list packages 列出包名adb shell pm list packages:列出所有的包名.adb shell dumpsys package:列出所有的安装应用的信息adb sh ...
- java中当static块和构造函数同时出现,顺序是?
静态块先于构造函数执行 class Student { int age; String name; static int count; public Student() { ...