最小生成树(MST)——Prim算法

       一个无向图的最小生成树由该无向图的那些连接相互连接的顶点的边构成的树,且使得该树的所有边的总权值和最小。最小生成树问题在实际生活中也广泛存在,例如:要在一个村庄修建一条公路,连通到村里的每户人家,选择怎么的路线铺设道路使得总的距离最短(造价最低)。

      最小生成树算法之一:Prim算法,将整个顶点集合分为两个子集U、V,U中存放已经在生成树中的顶点,V中存放未在生成树中的顶点。算法核心的每一步将从U、V中各选一顶点,使得边的权值w(u,v)最小,然后将该顶点v从V中移到U中,如此直到集合V为空,即完成。该过程如下图所示:


                                                                                                                Prim算法的基本步骤


在此以求解如下无向图的最小生成树为例,给出朴素Prim算法的实现代码:




C代码:

<span style="font-size:18px;">#include <stdio.h>
#include <stdlib.h>

#define Max 100
#define MAXCOST 0x7fffffff

int graph[Max][Max];//存放图中任意两顶点对应的边值,边值为MAXCONST即表示两顶点不相通

int Prim(int graph[][Max],int n)
{
	int lowcost[Max];//记录到终点i对应的边值,lowcost[i]=0表示点i已经在生成树中
	int start[Max];//记录终点i对应的起点,start[i]=0表示点i已经在最小生成树中
	int i,j,min,minid,sum;
	min=0;
	minid=0;

	//默认开始时将一号顶点加入生成树中,因此从二号顶点开始初始化。共n个顶点,生成树需要n-1条边
	for(j=2;j<=n;++j)
	{
		lowcost[j]=graph[1][j];
		start[j]=1;
	}
	lowcost[1]=0;//默认将一号顶点加入生成树
	sum=0;

	for(i=2;i<=n;++i)
	{
		min=MAXCOST;
		for(j=2;j<=n;++j)//查找满足条件(即起点在生成树中,终点在生成树外)的最小边值
		{
			if(lowcost[j]<min && lowcost[j]!=0)
			{
				min=lowcost[j];
				minid=j;
			}
		}
		//输出生成树中的该边
		printf("%c to %c: %d \n",start[minid]+'A'-1,minid+'A'-1,lowcost[minid]);
		sum+=lowcost[minid];
		lowcost[minid]=0;//将该点加入生成树中
		
		for(j=2;j<=n;++j)
		{
			if(graph[minid][j]<lowcost[j])//发现更小的权值(注:这句代码同时保证了点j不在生成树中且与点minid连通)
			{
				lowcost[j]=graph[minid][j];	//更新边值权值
				start[j]=minid; //更新边的起点
			}

		}
	}
	 
	return sum;//返回最小生成树的边值之和
}

/********************************/
/*测试
输入数据:
7 11
A B 7
A D 5
B C 8
B D 9
B E 7
C E 5
D E 15
D F 6
E F 8
E G 9
F G 11
*/
int main()
{
    int i, j, k, v, e;
	int x, y, cost;
	char chx, chy;
 
	//读取节点和边的数目 
	scanf("%d%d", &v, &e);
	getchar();

	// 初始化图,所有节点间距离为无穷大 
	for (i = 1; i <= v; i++)
	{
		for (j = 1; j <= v; j++)
		{
			graph[i][j] = MAXCOST;
		}
	}

	// 读取边信息 
	for (k = 0; k < e; k++)
	{
		scanf("%c %c %d", &chx, &chy, &cost);
		getchar();
		i = chx - 'A' + 1;
		j = chy - 'A' + 1;
		graph[i][j] = cost;
		graph[j][i] = cost;
	}

	//Prim算法
	cost=Prim(graph,v);

	// 输出最小权值和 
	printf("Total:%d\n", cost);
 
	return 0;	
}</span>
测试输出:









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值