点击查看代码
/*
输入样例:
6 10
0 1 4
0 4 1
0 5 2
1 2 6
1 5 3
2 3 6
2 5 5
3 4 4
3 5 5
4 5 3
输出样例:
15
*/
#include<cstdio>
#include<algorithm>
#pragma warning(disable:4996)
using namespace std;
const int maxn = 1000; //最多不超过1000个顶点
const int INF = 0x3fffffff; //表示无穷大
int n, m, G[maxn][maxn]; //顶点数,边数,邻接矩阵
int d[maxn]; //已知集合S与每个顶点的最短距离
bool vis[maxn] = { false }; //标记每个顶点是否已被访问,全部初始为false表示都未被访问
int prim() { //求解最小生成树的边权之和,没有传入初始参数,默认起点从0号顶点开始
fill(d, d + maxn, INF); //将d[]全部初始为INF,表示已知集合S与各点都不相连
d[0] = 0; //集合S与0号顶点最短距离为0
int ans = 0; //存储最小生成树的边权之和
for (int i = 0; i < n; i++) { //n个顶点循环n轮,每轮找出一个顶点
int u = -1, MIN = INF; //u存储d[u]最小的顶点,MIN存储最短距离d[u]
for (int j = 0; j < n; j++) { //枚举所有顶点
if (vis[j] == false && d[j] < MIN) { //查找在未访问的顶点中,d[j]最小的那个顶点
u = j; //用u记录j
MIN = d[j]; //MIN记录最短距离d[j]
}
}
if (u == -1) return -1; //如果u等于-1,则表示剩下的顶点与集合S都不相连,可以结束算法,返回-1表示无解
vis[u] = true; //否则设置u已被访问
ans += d[u]; //将与集合S距离最小的边加进最小生成树中,累加边权之和
for (int v = 0; v < n; v++) { //枚举所有顶点,查找u的邻接点v,判断能否以u为集合边界,使其邻接点与集合S距离更短
if (vis[v] == false && G[u][v] != INF) { //如果v未被访问,且u和v之间相连
if (G[u][v] < d[v]) { //如果以u为集合边界,能使集合S与v的距离更短(注意prim的判断距离与Dijkstra不同)
d[v] = G[u][v]; //更新d[v]
}
}
}
}
return ans; //返回最小生成树的边权之和
}
int main() {
int u, v, w; //每条边的两个端点u和v,边权w
scanf("%d%d", &n, &m);
fill(G[0], G[0] + maxn * maxn, INF); //邻接矩阵初始化全部边为INF,都不相连
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &w); //读取每条边的两个端点和边权
G[u][v] = G[v][u] = w; //无向边,要分别给两个方向的边权赋值
}
int ans = prim(); //求解最小生成树的边权之和,没有传入初始参数,默认起点从0号顶点开始
printf("%d\n", ans);
return 0;
}