Prim算法C语言实现(图解)

Prim算法:
图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。

Prim算法的描述:
已知带权连通图G(V,E),求其最小生成树T(Vnew,Enew),步 骤如下:
1.初始从G中任选一顶点v0,Vnew={v0},Enew={};
2.从V-Vnew中选取一顶点v,使得v到树T的距离最小,将v加入Vnew中,对应的边加入Enew中
3.重复步骤2,直到Vnew=V;

求下图的最小生成树

此为原始的加权连通图。每条边一侧的数字代表其权值。在这里插入图片描述

顶点D被任意选为起始点。顶点A、B、E和F通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。Vnew={D,A},Enew={(D,A)};

在这里插入图片描述
下一个顶点为距离D或A最近的顶点。B距D为9,距A为7,E为15,F为6。因此,F距D或A最近,因此将顶点F与相应边DF以高亮表示。Vnew={D,A,F} Enew={(D,A),(D,F)}
在这里插入图片描述
算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。
Vnew={D,A,F,B} Enew={(D,A),(D,F),(A,B)}

在这里插入图片描述
在当前情况下,可以在C、E与G间进行选择。C距B为8,E距B为7,G距F为11。点E最近,因此将顶点E与相应边BE高亮表示。Vnew={D,A,F,B,E} Enew={(D,A),(D,F),(A,B),(B,E)}
在这里插入图片描述
这里,可供选择的顶点只有C和G。C距E为5,G距E为9,故选取C,并与边EC一同高亮表示。Vnew={D,A,F,B,E,C} Enew={(D,A),(D,F),(A,B),(B,E),(E,C)}
在这里插入图片描述

顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG。Vnew={D,A,F,B,E,C,G} Enew={(D,A),(D,F),(A,B),(B,E),(E,C),(E,G)}在这里插入图片描述
所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。
在这里插入图片描述
Prim算法的代码

#include<stdio.h>
#include<string.h>
#define MaxSize 50
#define INF 10000000

double graph[MaxSize][MaxSize];
double prim(int n)                 //初始选取顶点0
{
    double lowcost[n],sum = 0;      //数组lowcost用来存储V-T中的顶点到T的最短距离,lowcost[i] = 0表示顶点i在树T中
    int count = 1,vetrix[n];        //vetrix[i]表示i到T中顶点vetrix[i]的距离最小,用于打印路径
    lowcost[0] = 0;
    for(int i = 1;i < n;i++)
    {
        lowcost[i] = graph[0][i];
        vetrix[i] = 0;
    }
    while(count < n)
    {
        double min = INF;
        int min_index;
        for(int i = 1;i < n;i++)
        {
            if(lowcost[i] != 0 && lowcost[i] < min) //找到权最小的边<vetrix[i],i>,其中vetrix[i]在T中,i在V-T中
            {
    	        min = lowcost[i];       //min记录最小的权值
    	        min_index = i;          //min_index记录最小边对应的顶点,即要加入T中的顶点
            }
        }
        sum += min;
        lowcost[min_index] = 0;
        count++;
        printf("%d->%d\n", vetrix[min_index],min_index);
        for(int i = 1;i < n;i++)
        {
	    if(lowcost[i] != 0 && lowcost[i] > graph[min_index][i])       //由于新加入T的顶点min_index,更新V-T中的顶点到T的最短距离,及对应的顶点
	        lowcost[i] = graph[min_index][i];
	        vetrix[i] = min_index;      
        }
    }
    return sum;
}

int main()
{
    int n, m, v1, v2;
    double w;
    scanf("%d %d",&n,&m);
    for(int i = 0;i < n;i++)
    {
        for(int j = 0;j < n;j++)
        {
            graph[i][j] = INF;
        }
    }
    for(int i = 0;i < m;i++)
    {
        scanf("%d %d %lf",&v1, %v2, &w);
        graph[v1][v2] = graph[v2][v1] = w;
    }
    printf("%lf\n",prim(n));
    return 0;
}

代码测试

输入:
10 18
0 1 12.7
0 8 12.4
0 7 13.4
1 2 12.6
1 8 12.1
2 3 12.9
2 4 24.2
2 8 23.6
2 9 23.3
3 4 22.2
3 5 22.1
3 6 15.3
4 5 14.4
5 9 12.5
6 7 21.7
6 9 13.2
7 8 21.8
8 9 12.8
输出:
0->8
8->1
1->2
8->9
9->5
2->3
9->6
0->7
5->4
116.300000

Prim算法的时间复杂度: O(n^2)
与图的顶点数目有关,另一种算法Krusal与边的数目有关;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值