最小生成树——普里姆(Prim)算法

Prim算法的基本思想是以顶点为主导地位;从起始顶点出发,通过选择当前可用的最小权值的边把其他顶点加入到生成树中来。设连通无向网为G(V,E),在普里姆算法中,将顶点集合V分成两个子集T和T'.

(1)T:当前生成树顶点集合。

(2)T':不属于当前生成树的顶点集合

具体实现过程如下:(1)从连通无向网中选择一个起始顶点u0,首先将它加入到集合T中;然后选择与u0关联的,具有最小权值的边(u0,v),将顶点v加入到集合T中。

(2)以后每一步从一个顶点(设为u)在T中,而另一个顶点(设为v)在T'中的各条边中选择权值最小边(u,v),把顶点v加入到集合T中。如此继续,直到网络中的所有顶点都加入到生成树集合T中为止。

例题:利用prim()算法求下图中的最小生成树,并输出依次选择的各条边及最终求得的最小生成树的权值。

分析说明:

(1)lowcost[]:存放顶点集合T'内到顶点集合T内各顶点权值最小的边的权值

(2)nearvex[]:记录顶点集合T'内各顶点距离顶点集合T内哪个顶点最近;当nearvex[i]==-1时,表示顶点i属于顶点T.

 

算法说明:使用prim算法求出上图的最小生成树,并且输出生成树的每条边。

测试数据:第一行为顶点数和边数,剩下m行每一行输入边的两个顶点,再输入边的权值

7 9

1 2 28

1 6 10

2 3 16

2 7 14

3 4 12

4 5 22

4 7 18

5 6 25

5 7 24 

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 9999999
#define MAXN 110
int n,m;
int Edge[MAXN][MAXN];
int lowcost[MAXN];
int nearvex[MAXN];
void prim(int u0)
{
    int i,j;
    int sumweight=0;
    for(i=1;i<=n;i++)///初始化lowcost数组和nearvex数组
    {
        lowcost[i]=Edge[u0][i];
        nearvex[i]=u0;
    }
    nearvex[u0]=-1;
    for(i=1;i<n;i++)///还剩n-1个顶点,所以需要n-1次循环
    {
        int MIN=INF;
        int v=-1;
        for(j=1;j<=n;j++)///找出T‘集合中距离T集合距离最小的顶点,并记录
        {
                if(nearvex[j]!=-1&&lowcost[j]<MIN)
                {
                    v=j;
                    MIN=lowcost[j];
                }
        }
        if(v!=-1)///v==-1表示没有找到权值最小的边
        {
            printf("%d %d %d\n",nearvex[v],v,lowcost[v]);
            nearvex[v]=-1;
            sumweight+=lowcost[v];
            for(j=1;j<=n;j++)///新加入顶点v,将剩余的未加入生成树的顶点距离T集合的最短距离改变。
            {
                if(nearvex[j]!=-1&&Edge[v][j]<lowcost[j])
                {
                    lowcost[j]=Edge[v][j];///顶点j距离集合T的最短距离改变
                    nearvex[j]=v;                 ///顶点j距离集合T的最近的顶点改变
                }
            }
        }
    }
    printf("weight of MST is %d\n",sumweight);
}
int main()
{
    int i,j;
    int u,v,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(Edge,0,sizeof(Edge));
        for(i=1;i<=m;i++)///输入m条边,存储到邻接矩阵中。
        {
            scanf("%d%d%d",&u,&v,&w);
            Edge[u][v]=Edge[v][u]=w;
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(i==j) Edge[i][j]=0;
                else if(Edge[i][j]==0) Edge[i][j]=INF;
            }
        }
        prim(1);
    }
    return 0;
}
/*
7 9
1 2 28
1 6 10
2 3 16
2 7 14
3 4 12
4 5 22
4 7 18
5 6 25
5 7 24
*/


 

 

 

 

 

prim()算法的简化版(只是为了单纯的求最小生成树而已),代码如下

 

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 30
#define maxint 0x3f3f3f3f
int map[MAXN][MAXN];
int n,m;
int visited[MAXN];
int lowcost[MAXN];
int prim()
{
    int i,j;
    int min,pos,sumweight=0;
     memset(visited,0,sizeof(visited));
     visited[1]=1;
     pos=1;
     for(i=1;i<=n;i++)
        if(i!=pos)
        lowcost[i]=map[pos][i];
     for(i=1;i<n;i++)
     {
         min=maxint;
         for(j=1;j<=n;j++)
            if(visited[j]==0&&lowcost[j]<min)///在还没有访问的顶点中选择距离集合T最近的一个
         {
             min=lowcost[j];
             pos=j;
         }
         sumweight+=min;
         visited[pos]=1;
         for(j=1;j<=n;j++)
            if(visited[j]==0&&map[pos][j]<lowcost[j])///没有被访问的。更新lowcost的值
            lowcost[j]=map[pos][j];
     }
     return sumweight;
}
int main()
{
    int i,j;
    int u,v,w;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(map,maxint,sizeof(map));
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            map[u][v]=w;
            map[v][u]=w;
        }
        int ans=prim();
        cout<<ans<<endl;
    }
}

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值