最小生成树~Prim算法

最小生成树是图论中的一个重要概念,Prim算法是从一个点开始逐步构建最小生成树。它与Dijkstra算法类似,每次选择与已选点集合连接的权值最小的边,直到所有点都被包含在内。这个过程可以理解为不断寻找最短的紫色边,即不在当前生成树内的、与树连接的最小权值边。通过不断更新距离并添加边,最终形成总权值最小的树。
摘要由CSDN通过智能技术生成

                                             最小生成树之~普里姆算法

         最小生成树是指从连好的图中(有n个点,多于(n-1)条边)选取n-1条边将n个点相互连接,并使得此树的总权值最小。完成此构造的方法著名的有两种,一个是kruskal算法,此算法是对每条边的权值进行排序,然后依次选取小的边添加到树上,并保证是一棵树(即不能产生回路)。另外一个就是prim算法,此算法是从点的角度来考虑。首先用map[][]二维数组存放两点间的权值,另外使用一个一维数组lowcost[]来存放与所选取的点相关联的权值,另外也使用一个mark[]数组用来标记已使用过的点。基本思想与最短路径中dijkstra算法十分相似。

        prim算法基本思想:

                从连通网络N={V,E},中选取一点S出发,选择与它相关联并且权值最小的边(S,V),将其顶点加入到生成树的顶点集合U中。以后每一步都选取一个不在顶点集合U中的点,使其到U的权值最小,然后将其加入到顶点集合U中。如此下去,直到网络中所有顶点均加入到生成树的顶点集合U中为止。

        用prim算法构造最小生成树的过程: 

                假设在构造过程中,树的顶点集U与边集均为红色,U集合之外的点为蓝色,连接红与蓝的边为紫色,则 最短的紫色边就是当前要寻找的边。每选取一个顶点就需对剩下的顶点作调整,更新其到树的顶点集U的距离。具体请参考代码:

#include<stdio.h>
#include<string.h>
#define INF 0x3f3f3f3f
int map[1010][1010];
int lowcost[1010];
int mark[1010];
int n,m;
int prim()
{
	int vir,min,sum=0;
	for(int i=1;i<=n;i++)			//将标记数组初始化为0,lowcost数组存放与起点1有关的点的权值 
	{
		mark[i]=0;
		lowcost[i]=map[1][i];
	}
	mark[1]=1;						//将起点标记 
	for(int i=1;i<n;i++)			//有n个点,所以需查找n-1次 
	{
		min=INF;
		for(int j=1;j<=n;j++)		//查找距树集合权值最小的点 
		{
			if(!mark[j]&&lowcost[j]<min)
			{
				min=lowcost[j];
				vir=j;
			}
		}
		if(min==INF)	break;
		sum+=min;					//最小权值累加 
		mark[vir]=1;				//标记已找到过的点
									//更新各点距树集合的距离 
		for(int j=1;j<=n;j++)
		{
			if(!mark[j]&&lowcost[j]>map[vir][j])
			{
				lowcost[j]=map[vir][j];
			}
		}
	}
	return sum;						//返回最小生成树的权值 
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)	//将map数组初始化为较大的值 
				map[i][j]=INF;
		for(int i=0;i<m;i++)
		{
			int x,y,cost;
			scanf("%d%d%d",&x,&y,&cost); 
			if(map[x][y]>cost)		//记录点与权值,若有重复取权值小的 
			{
				map[x][y]=cost;
				map[y][x]=cost;
			}
		}
		printf("%d\n",prim());		//输出此最小生成树的权值 
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值