最小生成树|Prim算法

最小生成树[模板]

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。

输入格式
第一行包含两个整数 N , M N,M N,M表示该图共有 N N N个结点和 M M M条无向边。

接下来 M M M行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi,Yi,Zi,表示有一条长度为 Z i Z_i Zi的无向边连接结点 X i , Y i X_i,Y_i Xi,Yi

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出orz。

输入输出样例

输入
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出
7

数据规模

对于 100 % 100\%% 100% 的数据: 1 ≤ N ≤ 5000 1\le N\le 5000 1N5000 1 ≤ M ≤ 2 × 1 0 5 1\le M\le 2\times 10^5 1M2×105

P r i m Prim Prim算法

最小生成树的两种算法: K r u s k a l Kruskal Kruskal算法和 P r i m Prim Prim算法, K r u s k a l Kruskal Kruskal在我的主页里,有兴趣可以去看看
其实,如果是单求最小生成树的话, K r u s k a l Kruskal Kruskal P r i m Prim Prim是等价的
K r u s k a l Kruskal Kruskal是将边的权值排序,不断选取合法的最小边的过程
P r i m Prim Prim则是将不断的选取能直接与目前已形成的生成树集合相连的点中最近的那个点,并更新其他点的值
例如下面这个图就是一个“生动形象”的 P r i m Prim Prim过程叙述:
在这里插入图片描述
(注:d(i)代表着i点到现有生成树的最短距离,图中标出的都是可以与现有生成树直接相连的点,其他的d赋值为无限大)

代码展示

#include<cstdio>
#include<cstdlib>
#include<iostream>

using namespace std;
/*最小生成树Prim未优化版*/

int book[100];//用于记录这个点有没有被访问过
int dis[100];//用于记录距离树的距离最短路程
int MAX = 99999;//边界值
int maps[100][100];//用于记录所有边的关系

int main()
{
    int i,j,k;//循环变量
    int n,m;//输入的N个点,和M条边
    int x,y,z;//输入变量
    int min,minIndex;
    int sum=0;//记录最后的答案

    cin>>n>>m;

    //初始化maps,除了自己到自己是0其他都是边界值
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
        {
            if(i!=j)
                maps[i][j] = MAX;
            else
                maps[i][j] = 0;
        }
    }

    for (i = 1; i <= m; i++)
    {
        cin>>x>>y>>z;//输入的为无向图
        maps[x][y] = z;
        maps[y][x] = z;
    }

    //初始化距离数组,默认先把离1点最近的找出来放好
    for (i = 1; i <= n; i++)
        dis[i] = maps[1][i];

    book[1]=1;//记录1已经被访问过了

    for (i = 1; i <= n-1; i++)//1已经访问过了,所以循环n-1次
    {
        min = MAX;//对于最小值赋值,其实这里也应该对minIndex进行赋值,但是我们承认这个图一定有最小生成树而且不存在两条相同的边
        //寻找离树最近的点
        for (j = 1; j <= n; j++)
        {
            if(book[j] ==0 && dis[j] < min)
            {
                min = dis[j];
                minIndex = j;
            }
        }

        //记录这个点已经被访问过了
        book[minIndex] = 1;
        sum += dis[minIndex];

        for (j = 1; j <= n; j++)
        {
            //如果这点没有被访问过,而且这个点到任意一点的距离比现在到树的距离近那么更新
            if(book[j] == 0 && maps[minIndex][j] < dis[j])
                dis[j] = maps[minIndex][j];
        }
    }

    cout<<sum<<endl;
}

申明

P r i m Prim Prim代码来自洛谷_October_巨佬的博客,别问我为什么不用自己的,因为这东西太难写了我现在还没懂

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值