#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack>
using namespace std;
const int MAXN =55;//节点数目
const int INF = 0x3f3f3f3f;
int len[MAXN];//已访问节点集合到其他点的最短距离
int mp[MAXN][MAXN];//所有点之间的距离
int vis[MAXN];//访问节点标记
int main()
{
int n, m;//n个点,m条线
int minpath;//最小生成树长度
int i,j,a, b, c;
while(cin >> n >> m)
{
if(m==0)
{/*点之间无线*//*单点或多点*/
if(n==1)
cout<<0<<endl;
else
cout<<-1<<endl;
continue;
}
minpath=0;
memset(mp, 0x3f, sizeof(mp));//初始化一个较大的值
for(i = 0;i < n;++i)//一定不要忘这个特殊的初始化
mp[i][i] = 0;
for(i = 0;i < m;++i)
{
cin >> a >> b >> c;//a到b路长c
mp[a][b] = min(mp[a][b], c);//若两点直连多条线,选短的
mp[b][a] = mp[a][b];//无向图,故此。 若有向图则不必
}
memset(len, 0x3f, sizeof(len));//初始化一个较大的值
for(i = 0;i < n;++i)
len[i] = mp[a][i];//随便选择一个点开始
memset(vis, 0, sizeof(vis));//初始化未访问
vis[a] = 1;
int v, mi;
//每次都 vis 一个点,加上上面一次 vis, 所以一共 vis n次
for(i = 1;i < n;++i)
{
//选出当前离 集合s 最近的点
mi = INF;
for(j = 0;j <n;++j)
{
if(!vis[j] && len[j] < mi)
{
mi = len[j];
v = j;
}
}
vis[v] = 1;
//更新 len
for(j = 0;j < n;++j)
if(!vis[j] && mp[v][j] < len[j])
len[j] = mp[v][j];
}
for(i=0;i<n;i++)
{
minpath+=len[i];
}
cout<<minpath<<endl;
}
return 0;
}
/*
1 0
5 0
2 3
1 0 37
0 1 17
1 0 68
3 7
1 0 19
2 1 11
2 0 7
0 2 5
2 1 89
0 2 91
1 0 32
5 7
1 0 5
2 1 7
1 3 8
4 3 11
2 4 10
0 4 6
3 1 12
*/
但有时候会因为输入的数据量过大而导致超时或者爆内存,所以不能暴力的用mp[MAXN][MAXN],用vector存储见另一篇博客。当使用vector还不足以AC,那就干脆考虑换成Kruskal吧。
注:若顶点数为n,边为e
prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边的数目无关,
而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。