最小生成树 prim算法

//最小生产成树prim算法

//两者区别:Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。Prim是以更新过的节点的连边找最小值,Kruskal是直接将边排序。


#define inf 123456789
#define maxn 5005
#define maxm 200005


//边采用链式前向星加边
struct Edge
{
    int to;//表示从这个表头 head[from] 所到达的边
    int w;//这条边所对应的权值
    int next;//指向head[from] 中最后一个表头在Edge数组中的位置
}edge[maxm<<1];//注意这个存储方式同时存储了方向,无向图要存储两倍(相互)



int head[maxn];//接邻表表头
int shortEdge[maxn];//记录已经加入点的集合到未加入点集合的最小距离(权值)
int cnt=0;//输入计数器
int result=0;//结果
int n,m;//n个点,m条边
int now=1;//从第一条边开始进行最小生成树prim算法
int total=0;//点总数
bool vit[maxn];//记录哪些点已经加入集合



//输入,读入数据的函数
void add(int from,int to,int w)
{
    edge[++cnt].to=to;
    edge[cnt].w=w;
    edge[cnt].next=head[from];
    head[from]=cnt;//更新表头所指向的最后一个元素
}




//读入数据
void init()
{
    scanf("%d%d",&n,&m);
    for(int i=1,f,t,w;i<=m;i++)
    {
        scanf("%d%d%d",&f,&t,&w);
        //注意无向图加两次,两点之间相互加
        add(f,t,w);add(t,f,w);
    }
}




//prim算法
int prim()
{
    //先把shortEdge数组初始化为最大值
    for(int i=2;i<=n;i++)
    {
        shortEdge[i]=inf;
    }

    //确认先从哪个点开始就把那个点的一行数据先加进来shortEdge数组进行初始化

    //这里默认从第一个点开始

    //计算出最小生成树集合到其它点集合距离的最小值,来初始化
    for(int i=head[1];i;i=edge[i].next)
    {
        shortEdge[edge[i].to]=min(shortEdge[edge[i].to],edge[i].w);
    }


    //初始化完开始继续连续不断加入集合到剩下点的最短边
    while(++total<n)
    {
        int temp=inf;
        int now1=now;
        //找出集合到剩下点之间的最小值
        vit[now]=true;//表及此点已经加入集合

        for(int i=1;i<=n;i++)
        {
             //判断此点是否已经加入点集
            if(!vit[i]&&shortEdge[i]<temp)
            {
                temp=shortEdge[i];
                now=i;//找到到剩下点集合的最短路径,就记录下点的标号
            }
        }

        result+=temp;//统计边的长度

         //加入最短边以后,更新shortEdge数组的值,到剩下点集的最短边
         //因为之前已经计算过已加入点集到剩下点的最短路径值,所以只需要拿新加入点到剩下点集的路径值和原来进行比较并更新即可
         for(int i=head[now];i;i=edge[i].next)
         {
             int temp1=edge[i].to;
             //如果新加入的点到这个点的距离更小且这个点不在最小生成树内就更新
             if(shortEdge[temp1]>edge[i].w&&!vit[temp1])
             {
                 shortEdge[temp1]=edge[i].w;
             }
         }
         if(now1==now) return 0;//如果找不到点了就返回输出
    }
    return result;

}



int main()
{
    init();
    prim();
    //判断是否符合最小生成树条件
    if(total==n) cout << result;
    else cout << "orz";

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值