Prim算法最小生成树

学习本算法之前,先来回顾一下Dijistra算法的核心:用一个数组dis来记录源点到各个顶点的距离,然后每次扫描dis数组,从中选择出离源点最近的顶点,看通过该顶点为始点的边能否更新源点到其他各个顶点的距离。

这里我们对这个方法稍稍改变一下,便能得到prim算法的核心。在这里用dis数组记录生成树中到各个顶点的最短距离,也就是说现在的最短距离不是到源点的最短距离,而是到已经被选入生成树中顶点的最短距离,即如果选取点t加入生成树,

dis[k] > e[t][k],那么dis更新为e[t][k],而不是dis[k]+e[t][k]。

明白核心之后,我们便可以随便选择一个点加入最小生成树,因为最小生成树肯定包含图中所有的点的,然后更新dis中到生成树的最小距离,然后再选出最短的一个dis[i],然后看通过i点是否能更新生成树的到其余顶点的距离,然后重复操作,直至选择出n个点为止,算法结束。

#include <iostream>
#include <cstdio>
#define inf 11111
using namespace std;
struct note{
	int b, w, next;
} edge[105];
int head[105], book[105], no, dis[105];
void init(int n){
	int i;
	for(i = 1; i <= n; ++i){
		book[i] = 0;
		head[i] = -1;
	}
}
void add(int a, int b, int w){
	edge[no].b = b;
	edge[no].w = w;
	edge[no].next = head[a];
	head[a] = no++;
}
int main(){
	int n, m, k, ans, ct, a, b, c, i, min, l;
	while(cin >> n >> m){
		init(n);
		no = 1;
		for(i = 1; i <= m; ++i){
			cin >> a >> b >> c;
			add(a, b, c);
			add(b, a, c);
		}
		for(i = 1; i <= n; ++i)
			dis[i] = inf;
		k = head[1];
		book[1] = 1;
		while(k != -1){
			if(!book[edge[k].b] && dis[edge[k].b] > edge[k].w)
				dis[edge[k].b] = edge[k].w;
			k = edge[k].next;
		}
		ct = 1;
		while(ct < n){
			min = inf+1;
			for(i = 1; i <= n; ++i){
				if(!book[i] && min > dis[i]){
					min = dis[i];
					l = i;
				}
			}
			++ct;
			book[l] = 1;
			ans += dis[l];
			k = head[l];
			while(k != -1){
				if(!book[edge[k].b] && dis[edge[k].b] > edge[k].w)
					dis[edge[k].b] = edge[k].w;
				k = edge[k].next;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

由堆优化的Dijistra算法,我们也会想能否通过堆来优化prim算法呢,其实是可以的,上代码。

#include <iostream>
#include <cstdio>
#include <queue>
#define inf 11111
using namespace std;
struct node{
	int b,w;
	node(int b, int w){
		this->b = b;
		this->w = w;
	}
	bool operator<(node n) const{
		return this->w > n.w;
	}
};
struct note{
	int b, w, next;
} edge[105];
int head[105], book[105], no, dis[105];
void init(int n){
	int i;
	for(i = 1; i <= n; ++i){
		dis[i] = inf;
		book[i] = 0;
		head[i] = -1;
	}
}
void add(int a, int b, int w){
	edge[no].b = b;
	edge[no].w = w;
	edge[no].next = head[a];
	head[a] = no++;
}
int main(){
	int n, m, k, ans, ct, a, b, c, i;
	while(cin >> n >> m){
		init(n);
		no = 1;
		for(i = 1; i <= m; ++i){
			cin >> a >> b >> c;
			add(a, b, c);
			add(b, a, c);
		}
		priority_queue<node> q;
		ans = 0;
		k = head[1];
		while(k != -1){
			q.push(node(edge[k].b, edge[k].w));
			dis[edge[k].b] = edge[k].w;
			k = edge[k].next;
		}
		ct = 1;
		book[1] = 1;
		while(ct < n){
			node x = q.top();
			q.pop();
			if(book[x.b]) continue;
			book[x.b] = 1;
			++ct;
			ans += x.w;
			k = head[x.b];
			while(k != -1){
				if(book[edge[k].b] == 0 && dis[edge[k].b] > edge[k].w){
					dis[edge[k].b] = edge[k].w;
					q.push(node(edge[k].b, edge[k].w));
				}
				k = edge[k].next;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

继续加油~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值