prim算法例题

点击查看代码
/*
输入样例:
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;
}
posted @ 2022-09-30 22:51  zhaoo_o  阅读(21)  评论(0编辑  收藏  举报