您的位置:首页 > 其它

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

2017-02-28 12:59 375 查看
      这次我写一些我对最小生成树的见解,最近做了一些这类型的题,相当于个人总结一下。

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



       如上图所示,假设这里有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;
}
      以上便是我对最小生成树的一点理解,如有错误,欢迎指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: