最小生成树prim算法与kruskal算法

最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。
这里写图片描述
分析:从一个初始点开始,每次获取与该点直连的点,并与之前获取的可连接的边比较,得到最小边,然后将连接的点并入集合(以后的点不能在包括他,要不然会形成回路),直到遍历完所有顶点纠结束。
代码:

#include<iostream>
const int INF = 10000;
using namespace std;
const int N = 6;
bool visit[N];
int dist[N] = { 0 };
int g[N][N] = { { INF, 6, 1, 5, INF, INF },  //INF代表两点之间不可达  
{ 6, 5, INF, INF, 3, INF },
{ 1, 5, INF, 5, 6, 4 },
{ 5, INF, 5, INF, INF, 2 },
{ INF, 3, 6, INF, INF, 6 },
{ INF, INF, 4, 2, 6, INF }
};

int prim(int cur){
	int index = cur;
	int sum = 0;
	for (int i = 0; i < N; i++){
		dist[i] = g[cur][i];//获取所有点与第一个点的距离
	}
	memset(visit, false, sizeof(visit));
	visit[cur] = true;//第一个点不能再包括
	cout << index << " ";//输出第一个点
	for (int i = 1; i < N; i++){
		int minor = INF;
		for (int j = 0; j < N; j++){//寻找最短边
			if (!visit[j] && dist[j] < minor){
				minor = dist[j];
				index = j;
			}
		}
		visit[index] = true;//最短边对应的另一个点纳入集合
		cout << index << " ";
		sum += minor;//最小树的总距离长度
		for (int j = 0; j < N; j++){
			if (!visit[j] && dist[j]>g[index][j]){//更新当前包括之前可连的点(最短),当前这个点a与其他点b的距离可能比之前的其他点c与点b的距离要短,所以要更新。
				dist[j] = g[index][j];
			}
		}
	}
	cout << endl;
	return sum;
}

int main(void){
	cout << prim(0) << endl;
	system("pause");
	return 0;

}

给自己留个坑,还有个kruskal算法也是求最小树的,大体思路就是用并查集来做,我现在还没开始写,之后补上。
思路:
把所有的线段以不降序列排序,然后从小到大遍历线段的两个节点,若两个节点不属于同一个集合,即不会形成回路,可以纳入集合,方法使用并查集的相关操作,
写好了,代码附上:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100;
struct node {
	int a, b, l;//线段的头结点和尾节点和长度
	bool operator<(node n1) {
		return n1.l > this->l;//以长度做不降序列
	}
};
node arr[N];
int parent[N], dist[N];//父节点和节点数
int m, n;
void creat() {
	for (int i = 0; i < n; i++) {
		parent[i] = i;
		dist[i] = 1;
	}
}
int find(int cur) {//查找根节点值
	if (parent[cur] != cur)parent[cur] = find(parent[cur]);
	return parent[cur];
}
void _union(int x, int y) {//合并节点
	int r1, r2;
	r1 = find(x); r2 = find(y);
	if (dist[r1] > dist[r2]) {//按秩合并,将节点数少的放在节点数多的下面
		parent[r2] = r1;
	}
	else if (dist[r1] < dist[r2]) {
		parent[r1] = r2;
	}
	else {
		parent[r1] = r2;
		dist[r2]++;
	}
}
void kruskal() {
	creat();
	int sum = 0;
	for (int i = 0; i < n; i++) {
		int x = arr[i].a, y = arr[i].b;
		if (find(x) != find(y)) {//如果两节点不在同一集合就可以合并
			sum += arr[i].l;
			_union(x, y);
		}
	}
	cout << sum<<endl;
}

int main(void) {
	cin >> m >> n;
	for (int i = 0; i < n; i++) {
		cin >> arr[i].a >> arr[i].b >> arr[i].l;
	}
	sort(arr, arr + n);
	kruskal();
	system("pause");
	return 0;
}

2019.3.6更新
在kruskal的代码里面,并查集的部分,dist数组我之前说的是节点数,现在想一想准确讲应该是这个集合的层数才对,集合a比集合b层数少,就将a放在b的下面,如果a和b相等,把a放在b的下面,会造成层数+1,这也应对了dist数组的自加。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值