#include <iostream>
#include<climits>
#include<vector>
#include<windows.h>
#define inf 0x3fffffff
using namespace std;
int n;
int prim(int &v0, vector< vector<int> >&adj);
void init_graph(vector< vector<int> >&adj);
int main()
{
int begin;
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << "please input the number of vertex:";
cin >> n;
vector< vector<int> >A(n, vector<int>(n));
init_graph(A);
cout << "please input begin vertex:";
cin >> begin;
cout << "The weight of minimum tree is " << prim(begin, A) << endl;
system("pause");
return 0;
}
void init_graph(vector< vector<int> >&adj)//对于对称矩阵可优化为只输入上三角和对角线元素
{
cout << "please input " << n << "-order adjacent matrix.\n";
for (int i = 0; i<n; ++i)
for (int j = 0; j<n; ++j)
cin >> adj[i][j];
}
int prim(int &v0, vector< vector<int> >&adj)//时间复杂度为O(n^2)
{
vector<bool>reach(n);
for (auto &x : reach)
x = false;
reach[v0] = true;
vector<int>mini;
for (int i = 0; i<n; ++i)
mini.push_back(adj[v0][i]);
int mintree = 0;
for (int j = 0; j<n; ++j)
{
int temp = v0, m = inf;
for (int t = 0; t<n; ++t)
if (!reach[t] && m>mini[t])//寻找未加入集合的节点所能构造的最小权值边
{
m = adj[v0][t];
temp = t;
}
if (m == inf) break;/*如果找不到可构造的最小权值边,提前结束循环,得到最终的最小生成树,
可能并没有遍历所有节点*/
mintree += m;
reach[temp] = true;//将节点temp加入已遍历集合
for (int s = 0; s<n; ++s)
if (!reach[s] && adj[temp][s]<mini[s]) mini[s] = adj[temp][s];
/*在已遍历的集合内,新加入的节点temp去更新权值库mini*/
}
return mintree;
}
代码测试结果如https://blog.csdn.net/weixin_43871369/article/details/88565694(同样的测试数据)
总结:Kruskal VS Prim(https://www.cnblogs.com/JoshuaMK/p/prim_kruskal.html)
方法上:Kruskal在所有边中不断寻找最小的边,Prim在U和V两个集合之间寻找权值最小的连接,共同点是构造过程都不能形成环。
时间上:Prim适合稠密图,复杂度为O(n * n),因此通常使用邻接矩阵储存,复杂度为O(e * loge),而Kruskal多用邻接表,稠密图 Prim > Kruskal,稀疏图 Kruskal > Prim。
空间上: Prim适合点少边多,Kruskal适合边多点少。