1,基本原理
MST性质:设 N =(V,E)是一个连通图,U是顶点集V的一个非空子集。若边(u,v)是一条具有最小权值的边,其中u属于U,v属于V-U,则必存在一棵包含边(u,v)的最小生成树。
举例:
如图,从v1点开始,将v1点加入到U中,寻找从U到V-U的权值最小的边,为1,将v3加入U中,再次寻找从U到V-U的权值最小的边,为2,将v4加入到U中,再次寻找从U到V-U的权值最小的边,为2,将v5加入到U中,再次寻找从U到V-U的权值最小的边,为3,将v2加入到U中,最小生成树完成。结果如下:
2,具体代码实现
注:这里因为把各个数据组都定义在了Prim函数里,所以显得函数体比较臃肿,其实主要代码只有两部分,一是更新从U到V-U中各点的最短边,二是寻找从U到V-U的最短边。
```cpp
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define Max 999999
void Prim(vector<vector<int> > V)
{
vector<int> d; //记录从U到V-U中各点的最短边
vector<int> U; //记录被加入到U中的点
vector<bool> visited; //记录点是否被加入U中
vector<int> M; //记录最终得到的各条边
d.resize(V.size());
visited.resize(V.size());
fill(visited.begin(), visited.end(), false);
U.push_back(0);
visited[0] = true;
fill(d.begin(), d.end(), Max);
d[0] = 0;
while (U.size() < V.size())
{
int x = U[U.size() - 1];
for (int i = 0; i < d.size(); ++i) //更新从U到V-U中各点的最短边
{
if (!visited[i] && V[x][i] < d[i])
{
d[i] = V[x][i];
}
}
int min = Max;
int index = 0;
for (int i = 0; i < d.size(); ++i) //寻找从U到V-U的最短边
{
if (d[i] < min && !visited[i])
{
min = d[i];
index = i;
}
}
if (index == 0)
{
cout << "该图不连通" << endl;
return;
}
visited[index] = true;
U.push_back(index);
M.push_back(min);
}
for (int i = 0; i < M.size(); ++i) //输出所得最小生成树的各条边
{
cout << M[i] << " ";
}
}
int main()
{
int n = 0;
int m = 0;
int u, v, w;
cout << "输入节点个数:" << endl;
cin >> n;
cout << "输入边数:" << endl;
cin >> m;
vector<vector<int> > V;
V.resize(n);
for (int i = 0; i < n; ++i)
{
V[i].resize(n);
for (int j = 0; j < n; ++j)
{
V[i][j] = Max;
}
}
cout << "输入各条边的信息:" << endl;
for (int i = 0; i < m; ++i)
{
cin >> u >> v >> w;
V[u][v] = V[v][u] = w;
}
Prim(V);
return 0;
}
输入输出信息:![在这里插入图片描述](https://img-blog.csdnimg.cn/20201002091216518.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2MDI3MjQz,size_16,color_FFFFFF,t_70#pic_center)