Prim算法的具体实现

【问题描述】
 已知含有n个顶点(编号从1开始)的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出 (三元组数据结构见教材5.3.2节),只给出不包括主对角线元素在内的下三角这部分的元素,且不包括不邻接的顶点对。请采用Prim算法,求该连通图从1号顶点出发的最小生成树的权值之和。
【输入形式】
 第1行给出图中结点个数n和三元组的个数num,之后每行给出一个三元组,数之间用1个空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
 求解的最小生成树的各条边、各边的权值、最小生成树的权值和

Prim算法是求解最小生成树的一种经典算法,它的主要思想可以归纳如下:从一个顶点开始,寻找与它相连的权值最小的边,把对应的顶点加入,再在所有相邻的顶点中找权值最小的边,直到覆盖了全部顶点,此时的边数为顶点数-1

首先是变量的初始化

int a[105][105]={0};
int n,m,dist[120],parent[120]={0},total;

a[105]105]就是邻接矩阵,dist[]数组用来记录每个顶点到树的距离,如果该顶点已经成为了树的一部分,则dist[i]=0,parent数组用来记录父亲节点

void prim()
{
	for(int i=2;i<=n;i++)
	{
		parent[i]=1;
		if(a[1][i])
			dist[i]=a[1][i];
		else
			dist[i]=99999;	
	}
	dist[1]=0;
	parent[1]=-1;
	while(1)
	{
		int v=Find();
		if(v==-1)
			break;
		total+=dist[v];
		printf("%d-%d:%d\n",parent[v],v,a[v][parent[v]]);
		dist[v]=0;
		for(int i=2;i<=n;i++)
		{
			if(dist[i]!=0&&a[i][v]<99999)
			{
				if(a[i][v]!=0&&a[i][v]<dist[i])
				{
					dist[i]=a[i][v];
					parent[i]=v;
				}
			}
		}
	}
}

上面的代码段就是主要函数实现,首先先对parent数组和dist数组进行初始化,所有节点的父亲节点默认为1,初始的dist值为每个节点到节点1的权重,如果没有边相连就是无穷大,dist[1]设定为0

首先先给出我们的查找函数Find,这个函数是为了找到到已有生成树权值最小的点,如果没找到则返回-1

int Find()
{
	int minv,minn=99999;
	for(int i=2;i<=n;i++)
	{
		if(dist[i]!=0&&dist[i]<minn)
		{
			minn=dist[i];
			minv=i;
		}
	}
	if(minn<99999)
		return minv;
	else
		return -1;
}

我们调用Find函数得到一个返回值v,把它的边权加入到total中,修改它的dist值为0,接下来对剩下的点进行维护,观察是否有点的dist值因为v的加入而发生改变,如果有,则及时更新。

如果我们调用Find函数返回的值为-1,那么说明已经得到了最小生成树,此时便跳出循环

下面给出完整代码

#include<bits/stdc++.h>
using namespace std;
int a[105][105]={0};
int n,m,dist[120],parent[120]={0},total;
int Find()
{
	int minv,minn=99999;
	for(int i=2;i<=n;i++)
	{
		if(dist[i]!=0&&dist[i]<minn)
		{
			minn=dist[i];
			minv=i;
		}
	}
	if(minn<99999)
		return minv;
	else
		return -1;
}
void prim()
{
	for(int i=2;i<=n;i++)
	{
		parent[i]=1;
		if(a[1][i])
			dist[i]=a[1][i];
		else
			dist[i]=99999;	
	}
	dist[1]=0;
	parent[1]=-1;
	while(1)
	{
		int v=Find();
		if(v==-1)
			break;
		total+=dist[v];
		printf("%d-%d:%d\n",parent[v],v,a[v][parent[v]]);
		dist[v]=0;
		for(int i=2;i<=n;i++)
		{
			if(dist[i]!=0&&a[i][v]<99999)
			{
				if(a[i][v]!=0&&a[i][v]<dist[i])
				{
					dist[i]=a[i][v];
					parent[i]=v;
				}
			}
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int s=1;s<=m;s++)
	{
		int i,j,k;
		cin>>i>>j>>k;
		a[i][j]=k;
		a[j][i]=k;
	}
	prim();
	cout<<total;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值