Prim算法求最小生成树 附hdoj1162

本文介绍使用Prim算法求解最小生成树(MST)的方法,包括朴素版本的详细步骤和代码实现,通过邻接矩阵输入边权重,并最终输出最小生成树的边及其权重总和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下测试数据所用的图为:


#include <iostream>
using namespace std;
//Prim算法

//朴素版本
/*
key[所有] = INF;done[所有] = false;par[i] = -1;
根据指定树根r,设置key[r] = 0;
执行n次
{
选择key[]最小的一个点,记录为x
done[x] = true
对于所有x可达的点,更新它们key[]及par[];
}
*/

//高级版本
/*
  选择key[]最小的一个点,一般用堆实现的优先队列来实现——
  不用执行n次,换成while(优先队列非空),之前先把树根或者全部结点放入优先队列
  while (!q.empty())
  {
  对于出队的结点x,done[x] = ture; 更新所有与x相邻结点的key[]和par[],若有更新则把结点放入队列
  //但是这样同一个结点可能被多次放入队列,没关系,优先队列会选出同一个结点中更优的那个结点(也就是最后放入的)
  //而处理了这个结点则会标记done[]为true,对于选出来的结点若是done=true(即纳入MST集合)的结点则忽略
  //注意这个忽略操作要在标记操作之前!否则都会被忽略掉。
  }
*/

//朴素版本实现
//读入一个邻接矩阵
const int N = 110;
const int INF = 999999999;
const int NUL = -1;
int key[N]; //类似dijkstra中的d
int par[N]; //记录父母结点
bool done[N];
int w[N][N];

struct MST{
	int from, to;
	int weight;
};

MST mst[N];

char trans(int i)
{
	return i+'A';
}

int main()
{
	int n, min, weight_sum, x, cnt = 0;
	
	cin >> n;
	for (int i = 0; i != n; i++) {
		for (int j = 0; j != n; j++) {
			cin >> w[i][j];
		}
	}
	memset(done, false, sizeof (done));
	for (int i = 0; i != n; i++) {
		key[i] = INF;
		par[i] = NUL;
	}

	//假定MST(最小生成树)树根选结点0
	int root = 0;
	key[root] = 0;
	
	//循环n次
	for (int k = 0; k != n; k++) {
		min = INF;
		for (int i = 0; i != n; i++) {
			if (!done[i] && key[i] < min) {
				min = key[i];
				x = i;
			}
		}
		done[x] = true;
		//存入MST
		if (x != root) {
			mst[cnt].from = par[x];
			mst[cnt].to = x;
			mst[cnt].weight = w[par[x]][x];
			weight_sum += mst[cnt].weight;
			cnt++;
		}
		for (int y = 0; y != n; y++) {
			if (w[x][y] != 0 && key[y] > w[x][y]) {
				key[y] = w[x][y];
				par[y] = x; //par[y]指向来源即父母
			}
		}
		
	} //循环n次
	
	//输出MST
	for (int i = 0; i != n-1; i++) {
		cout << trans(mst[i].from) << "->" << trans(mst[i].to)
			 << " " << "weight = " << mst[i].weight << endl;
	}
	cout << "weight_sum = " << weight_sum << endl;
	return 0;
}

/*
  参考数据
  图片参考百度百度kruskal的图片
  矩阵

7

0 7 0 5 0 0 0
7 0 8 9 7 0 0
0 8 0 0 5 0 0
5 9 0 0 15 6 0
0 7 5 15 0 8 9
0 0 0 6 8 0 11
0 0 0 0 9 11 0

输出:
A->D weight = 5
D->F weight = 6
A->B weight = 7
B->E weight = 7
E->C weight = 5
E->G weight = 9
weight_sum = 39

 */


同样,为了验证代码的正确性,可以测试一下 hdoj1162

AC代码:

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;

const int N = 110;
const double INF = 999999999.0;
const int NUL = -1;

double X[N];
double Y[N];
double key[N]; //类似dijkstra中的d
int par[N]; //记录父母结点
bool done[N];
double w[N][N];

inline double dist(double x1, double x2, double y1, double y2)
{
	return sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
}

int main()
{
	int n;
	
	while (cin >> n) {
		int min, x, cnt = 0;
		double weight_sum = 0.0;
		//转为邻接矩阵
		for (int i = 0; i != n; i++) {
			cin >> X[i] >> Y[i];
		}
		for (int i = 0; i != n; i++) {
			for (int j = 0; j != n; j++) {
				if (i == j)
					w[i][j] = 0.0;
				else {
					w[i][j] = dist(X[i], X[j], Y[i], Y[j]);
					w[j][i] = w[i][j];
				}
			}
		}
		memset(done, false, sizeof (done));
		for (int i = 0; i != n; i++) {
			key[i] = INF;
			par[i] = NUL;
		}
		//假定MST(最小生成树)树根选结点0
		int root = 0;
		key[root] = 0;
		//循环n次
		for (int k = 0; k != n; k++) {
			min = INF;
			for (int i = 0; i != n; i++) {
				if (!done[i] && key[i] < min) {
					min = key[i];
					x = i;
				}
			}
			done[x] = true;
			//计算MST的权和
			if (x != root) {
				weight_sum += w[par[x]][x];
			}
			for (int y = 0; y != n; y++) {
				if (w[x][y] != 0 && key[y] > w[x][y]) {
					key[y] = w[x][y];
					par[y] = x; //par[y]指向来源即父母
				}
			}
		} //循环n次
		printf("%.2lf\n", weight_sum);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值