最小生成树[模板]
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。
输入格式
第一行包含两个整数
N
,
M
N,M
N,M表示该图共有
N
N
N个结点和
M
M
M条无向边。
接下来 M M M行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi,Yi,Zi,表示有一条长度为 Z i Z_i Zi的无向边连接结点 X i , Y i X_i,Y_i Xi,Yi。
输出格式
如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出orz。
输入输出样例
输入
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出
7
数据规模
对于 100 % 100\%% 100% 的数据: 1 ≤ N ≤ 5000 1\le N\le 5000 1≤N≤5000, 1 ≤ M ≤ 2 × 1 0 5 1\le M\le 2\times 10^5 1≤M≤2×105
P r i m Prim Prim算法
最小生成树的两种算法:
K
r
u
s
k
a
l
Kruskal
Kruskal算法和
P
r
i
m
Prim
Prim算法,
K
r
u
s
k
a
l
Kruskal
Kruskal在我的主页里,有兴趣可以去看看
其实,如果是单求最小生成树的话,
K
r
u
s
k
a
l
Kruskal
Kruskal和
P
r
i
m
Prim
Prim是等价的
K
r
u
s
k
a
l
Kruskal
Kruskal是将边的权值排序,不断选取合法的最小边的过程
P
r
i
m
Prim
Prim则是将不断的选取能直接与目前已形成的生成树集合相连的点中最近的那个点,并更新其他点的值
例如下面这个图就是一个“生动形象”的
P
r
i
m
Prim
Prim过程叙述:
(注:d(i)代表着i点到现有生成树的最短距离,图中标出的都是可以与现有生成树直接相连的点,其他的d赋值为无限大)
代码展示
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
/*最小生成树Prim未优化版*/
int book[100];//用于记录这个点有没有被访问过
int dis[100];//用于记录距离树的距离最短路程
int MAX = 99999;//边界值
int maps[100][100];//用于记录所有边的关系
int main()
{
int i,j,k;//循环变量
int n,m;//输入的N个点,和M条边
int x,y,z;//输入变量
int min,minIndex;
int sum=0;//记录最后的答案
cin>>n>>m;
//初始化maps,除了自己到自己是0其他都是边界值
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if(i!=j)
maps[i][j] = MAX;
else
maps[i][j] = 0;
}
}
for (i = 1; i <= m; i++)
{
cin>>x>>y>>z;//输入的为无向图
maps[x][y] = z;
maps[y][x] = z;
}
//初始化距离数组,默认先把离1点最近的找出来放好
for (i = 1; i <= n; i++)
dis[i] = maps[1][i];
book[1]=1;//记录1已经被访问过了
for (i = 1; i <= n-1; i++)//1已经访问过了,所以循环n-1次
{
min = MAX;//对于最小值赋值,其实这里也应该对minIndex进行赋值,但是我们承认这个图一定有最小生成树而且不存在两条相同的边
//寻找离树最近的点
for (j = 1; j <= n; j++)
{
if(book[j] ==0 && dis[j] < min)
{
min = dis[j];
minIndex = j;
}
}
//记录这个点已经被访问过了
book[minIndex] = 1;
sum += dis[minIndex];
for (j = 1; j <= n; j++)
{
//如果这点没有被访问过,而且这个点到任意一点的距离比现在到树的距离近那么更新
if(book[j] == 0 && maps[minIndex][j] < dis[j])
dis[j] = maps[minIndex][j];
}
}
cout<<sum<<endl;
}
申明
此 P r i m Prim Prim代码来自洛谷_October_巨佬的博客,别问我为什么不用自己的,因为这东西太难写了我现在还没懂