【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 ...
随机推荐
- Springmvc入门基础(六) ---拦截器应用demo
1.拦截器定义 Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理. 2.拦截器demo demo需求: 拦截用户请求,判断用 ...
- Java连接ArtemisMQ,出现Timed out waiting to receive cluster topology. Group:null异常
完整异常内容:org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JM ...
- Java 中你怎样唤醒一个阻塞的线程?
在 Java 发展史上曾经使用 suspend().resume()方法对于线程进行阻塞唤醒,但 随之出现很多问题,比较典型的还是死锁问题. 解决方案可以使用以对象为目标的阻塞,即利用 Object ...
- 什么是 Spring Framework?
Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度.它是轻量级.松 散耦合的.它具有分层体系结构,允许用户选择组件,同时还为 J2EE 应用程序 开发提供了一个有凝聚力的框架.它可以集成其 ...
- 爬虫-数据解析-xpath
xpath 解析 模块安装 : pip install lxml xpath的解析原理 实例化一个etree类型的对象,且将页面源码数据加载到该对象中 需要调用该对象的xpath方法结合着不同形式的x ...
- C语言中的bool类型 stdbool.h
C语言的C99标准中已经可以使用bool类型了,但有些小伙伴可能受制于编译器等原因还无法使用,我就从最新版的VS2019 中,找到了stdbool.h这个头文件的定义,其实就是一堆宏的定义,代码如下: ...
- c语言中的字面量
在计算机科学中,字面量(literal)是用于表达源代码中一个固定值的表示法(notation). 几乎所有计算机编程语言都具有对基本值的字面量表示,诸如:整数.浮点数以及字符串: 而有很多也对布尔类 ...
- 顺利通过EMC实验(18)
- js如何获取iframe页面内的对象
简单介绍iframe标签,所有的浏览器都支持<iframe>标签,iframe 元素会创建包含另外一个文档的内联框架(即行内框架).通常我们常用的iframe标签的属性有:width(if ...
- CSS的inline、block与inline-block
基本知识点 行内元素一般是内容的容器,而块级元素一般是其他容器的容器,行内元素适合显示具体内容,而块级元素适合做布局. 块级元素(block):独占一行,对宽高的属性值生效:如果不给宽度,块级元素就默 ...