最小生成树——prim算法(个人总结)

      这次我写一些我对最小生成树的见解,最近做了一些这类型的题,相当于个人总结一下。

      最小生成树,比如几个村庄之间给出几个每两个村庄之间需要修多长的路,然后要你选择修路方式让所有村庄连通,而且要让修路的长度最小,当然也可以对应修路的消耗。这种情况下就要用到最小生成树。


       如上图所示,假设这里有A,B,C,D,E五个村庄,现在准备在这五个村庄之间修路,然后对应每两个村庄之间修路有一个需要修路的长度(也可以表示修这条路需要消耗的资源什么的),为了使五个村庄连通并且让修路长度最短。应该怎么办呢。

       这时我们可以随便找一个村庄开始修路,比如从A开始,然后它可以修3条路到其他村庄,这时我们选择长度最短的AD,现在我们修了长度为4的路了,并且连通了村庄D,然后再找下一条路,也就是现在A和D村庄能够到达其他村庄的一条路,这时我们还是找最小的,也就是DC长度最短,连通村庄C,一共修路长度为7了,然后又继续找,依次寻找最短的那一条,就会再找到DE和AB,最后最小需要修路长度为17,就可以得到我们想要的结果了。

      接下来是代码:

#include <stdio.h>
#include <string.h>
#define MAXN 1005
#define INF 0x3f3f3f3f
int vis[MAXN], contact[MAXN][MAXN],dis[MAXN];//vis用来判断当前点是否已经连通,contact数组
//存放两个点间连接的长度,dis在接下来的操作中用到
int main()
{
	int n, m, i, j, a, b, len, k, min, sum;
	scanf("%d%d", &n, &m);
	memset(contact, 0, sizeof(contact));
	memset(vis, 0, sizeof(vis));
	for (i = 1; i <= m; i++)
	{
		scanf("%d%d%d", &a, &b, &len);
		//这里要判断一下两个点间是否已经有过可以连通的路线,没有直接输入数组中
		//如果有取小的那一条,但是要看题意,如果说明了两点间有且只有一条路线,那么就不用判断
		if (contact[a][b] == 0)
		{
			contact[a][b] = len;
			contact[b][a] = len;
		}
		else if (contact[a][b] > len)
		{
			contact[a][b] = len;
			contact[b][a] = len;
		}
	}
	for (i = 1; i <= n; i++)
	{
		dis[i] = contact[1][i];//dis这里存放的是点1到其他点的距离,为0,就是没有路线
		//下面的对dis的操作就是更新现在连通的点到其他点的最短距离
	}
	vis[1] = 1;
	sum = 0;
	for (i = 1; i <= n; i++)
	{
		min = INF;
		for (j = 1; j <= n; j++)
		{
			if (!vis[j] && dis[j] && min > dis[j])//注意dis保存的值为0的情况
			{
				min = dis[j];
				k = j;//k保存max对应的点
			}
		}
		if (min == INF)
		{
			continue;//min值没改变就证明当前连通点不能够连通其他点了
		}
		vis[k] = 1;//连通的点进行标记
		sum += min;
		for (j = 1; j <= n; j++)
		{
			if (!vis[j] && (contact[k][j] < dis[j] || !dis[j])&&contact[k][j])//先判断是否是已经连通的点
			//然后判断dis如果为0,然后连通的路线不为0就可以直接赋值,不然就取小
			{
				dis[j] = contact[k][j];
			}
		}
	}
	printf("%d\n", sum);
	return 0;
}
      以上便是我对最小生成树的一点理解,如有错误,欢迎指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值