一、最小生成树的概念
图分为无向图和有向图,其中包括无权,有权(正权负权)图。
定义:无向带权图G顶点个数为 m ,由G中 m 个点和 m - 1 条边构成的连通子图称为G的一条支撑树,也叫生成树。 边权之和最小的支撑树叫做最小支撑树(MST)。
最小支撑树无回路
二、算法分析
1.Prim算法(逐点加入)
Prim算法更适用于稠密图(点少边多)。
过程图解
2.Kruskal算法(逐边加入)
利用并查集实现,将每个连通分量看作一个集合,顶点看作集合元素,每次查询一条权值最小的边,查询该边的两端是否在同一个集合内,若不在就将这两个集合合并,将该边加入支撑树中。Kruskal算法更适用于稀疏图(点多边少)。
过程图解
三、求最小支撑树例题——Prim
1. 题目说明
2. 代码实现
#include<iostream>
using namespace std;
#define WQ 65535//有符号的最大值表示无穷大
int edge[2000][2000];//邻接矩阵
long long sum;//权值之和
int TE[1000];
int lowcost[2000];//最小权值数组
int U[2000];
bool flag = false;
//构建邻接矩阵
void CreatGraph(int n, int e) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
edge[i][j] = WQ;
}
}
for (int k = 0; k < e; k++) {
int a, b, c;
cin >> a >> b >> c;
edge[a][b] = c;
edge[b][a] = edge[a][b];
}
}
void Prim(int n, int e) {
flag = false;
for (int i = 1; i <= n; i++) {
lowcost[i] = edge[1][i];
U[i] = 1;
}
U[1] = -1;
int k = 1;
for (int i = 1; i <= n - 1; i++) {
int v = 0;
int min = WQ;//无穷大
for (int j = 1; j <= n; j++) {
if (U[j] != -1 && lowcost[j] < min) {//初始化
v = j;
min = lowcost[j];
}
}
if (v == 0) {
flag = true;
printf("There is no minimum spanning tree.\n");
return;
//图不连通
}
TE[k] = lowcost[v];
k = k + 1;
lowcost[v] = 0;
U[v] = -1;
for (int j = 1; j <= n; j++) {
if (U[j] != -1 && edge[v][j] < lowcost[j]) {//更新权值
lowcost[j] = edge[v][j];
U[j] = v;
}
}
}
//return 0;
}
//主函数
int main() {
int n;//顶点数
int e;//边数
while (scanf("%d%d", &n, &e) != EOF)
{
CreatGraph(n, e);//构建邻接矩阵
Prim(n, e);
if (flag == false) {
for (int i = 1; i <= e; i++) {
sum += TE[i];
}
cout << sum << endl;
}
}
return 0;
}