最小生成树-Prim算法

最小生成树minimal-spanning-tree(概念就不具体介绍了)有两种基于不同贪心选择的算法,一个为Prim算法,一个为Kruskal算法。

Prim和Dijkstra算法很像,只是少了些东西。它将结点分为两类,一类是已经选择了的确定的,构建好了的mst的结点,另一类是还没确定的未选择的结点。

流程是这样的:(括号内为权值),U集合:MST的点集合,V-U:未选择的点集合

1.首先初始化开始结点U,然后把所有能够与U相连的边为候选边

这里就是数组初始化操作了;

1      int sum=0;
2     for(int i=1;i)
3     {
4         dis[i]=map[1][i];//初始化所有点到结点1的距离
5         vis[i]=false;//所有点开始都未被访问
6     }
7     vis[1]=true;//结点1标志为true

最小生成树-Prim算法

开始时U是结点1,然后找到所有与1相连的边(dist[i][j]!=0),分别是1-6(10),1-2(28),所以找出最小的(6

 1 for(int i=2;i)
 2     {
 3         int MIN=INF;//从当前节点u到与u联通的子节点的最小权值
 4         int k=-1;
 5         for(int j=1;j)//遍历每个点
 6         {
 7             if(!vis[j]&&dis[j]<MIN)//未被访问且距离还小,那就待定选你了,看看还有没有距离更短的
 8             {
 9                 MIN=dis[j];//更新最小值,这个dis表式这个点到已知mst中一点的最小值
10                 k=j;//标记结点号
11             }
12         }
13         vis[k]=true;//u->a->b  k->b //置已经访问
14         sum+=MIN;//u->k求生成树的路径和
15         ...

16         ...

17        ...

18 }

最小生成树-Prim算法

然后我们发现,左部分和右部分只有两条边相连了,那么继续找最短边就行6-5(25)

最小生成树-Prim算法

再比较1-2(28),5-7(24),5-4(22),取出最小边是5-4(22),更新图

最小生成树-Prim算法

继续比较选出最短边,这时有4个边要比较了,1-2(28),5-7(24),4-7(18),4-3(12),找出最短边4-3(12),更新图

最小生成树-Prim算法

继续比较4个个边,1-2(28),5-7(24),4-7(18),3-2(16),找出最短的16,更新图

最小生成树-Prim算法

好了,最后已给点7,应该很容易看出来它是2连接的,因为14是最短的。

所以MST图是这样

最小生成树-Prim算法

后半段的代码是这样的

1 for(int j=1;j//带已经找到点k的情况下,找结点j
2         {
3             if(!vis[j]&&dis[j]>map[k][j])
4             {//j未访问且 j到mst中点的最小值还大于从k到j的距离,那么就
5 //要更新这段距离
6                 dis[j]=map[k][j];//clost[j] = k;
7             }
8         }

看这个图

比如说开始先初始化,dist[6] =10;dist[4]=1,即结点6和4到结点1的最短距离为dist数组,然后我找到了最短路1-4,并且发现原来的1-6(10)大于6-4(5),所以更新dist[6]=4,他表示结点6到已知MST的某个点的最短的那个距离,也可以将那个点记录在clost数组中,以便需要。

完整代码,其实很简单的

邻接矩阵:

最小生成树-Prim算法最小生成树-Prim算法
 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 const int INF=0x3f3f3f3f;
 6 const int MAXN=1005;
 7 int map[MAXN][MAXN];   //map[i][j]   ----  i->j =v
 8 int dis[MAXN];     //
 9 bool vis[MAXN];
10 int n;
11 void init()
12 {
13     for(int i=0;i<=n;i++)
14     {
15         for(int j=0;j<=n;j++)
16         {
17             if(i!=j)map[i][j]=INF;
18             else map[i][j]=0;
19         }
20     }
21 }
22 int Prim()
23 {
24     int sum=0;
25     for(int i=1;i<=n;i++)
26     {
27         dis[i]=map[1][i];
28         vis[i]=false;
29     }
30     vis[1]=true;
31     for(int i=2;i<=n;i++)
32     {
33         int MIN=INF;//从当前节点u到与u联通的子节点的最小权值
34         int k=-1;//u->v k=v;
35         for(int j=1;j<=n;j++)
36         {
37             if(!vis[j]&&dis[j]<MIN)
38             {
39                 MIN=dis[j];
40                 k=j;
41             }
42         }
43         vis[k]=true;//u->a->b  k->b
44         sum+=MIN;//u->k
45         for(int j=1;j<=n;j++)
46         {
47             if(!vis[j]&&dis[j]>map[k][j])
48             {
49                 dis[j]=map[k][j];
50             }
51         }
52     }
53     return sum;
54 }
55 int main()
56 {
57     cin>>n;
58     init();
59     for(int i=1;i<=n;i++)
60     {
61         for(int j=1;j<=n;j++)
62         {
63             int v;
64             cin>>v;
65             if(map[i][j]>v)
66             {
67                 map[i][j]=map[j][i]=v;
68             }
69         }
70     }
71     int c;
72     cin>>c;
73     for(int i=1;i<=c;i++)
74     {
75         int a,b;
76         cin>>a>>b;
77         map[a][b]=map[b][a]=0;
78     }
79     /for(int i=1;i<=n;i++)>80     {
81         int a,b,v;
82         cin>>a>>b>>v;
83         /if(map[a][b]>v)
84         {
85             map[a][b]=map[b][a]=v;
86         }
87         map[a][b]=v;
88     }*/
89     cout<<prim()<<endl;
</prim()<<90     return 0;
91 }

View Code

邻接表:

最小生成树-Prim算法最小生成树-Prim算法
  1 /**********
  2     > File Name: p3366.cpp
  3     > Author: YeGuoSheng
  4     > Description:
  5 最小生成树模板 、如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
  6 输入格式
  7 第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,m<=200000)>  8
  9 接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
 10
 11 输出格式
 12 输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
 13 输入输出样例
 14 输入 #1 复制
 15 4 5
 16 1 2 2
 17 1 3 2
 18 1 4 3
 19 2 3 4
 20 3 4 3
 21 输出 #1 复制
 22 7
 23     > Created Time: 2019年08月02日 星期五 10时26分54秒
 24  ***********/
 25
 26 #include
 27 #include
 28 #include
 29 #include
 30 #include
 31 #include
 32 #include
 33 #include<set>
 34 #include
 35 #include
 36 #include<string>
 37 #include
 38 #include
 39 using namespace std;
 40 const int maxn = 500005;
 41 const int INF = 0x3f3f3f3f;
 42 int head[maxn];
 43 int dis[maxn];
 44 int vis[maxn];
 45 int n,m;//顶点数,边数
 46 struct edge
 47 {
 48     int v;
 49     int w;
 50     int next;
 51 }edges[maxn<<1];
 52
 53 int cnt = 1;
 54
 55 void Add(int x,int y,int w)
 56 {
 57    edges[cnt].v = y;
 58    edges[cnt].w = w;
 59    edges[cnt].next = head[x];
 60    head[x] = cnt ++;
 61 }
 62
 63 void Init()
 64 {
 65     cin>>n>>m;
 66     int x,y,w;
 67     for(int i = 1;i <=>)

68 { 69 70 cin>>x>>y>>w; 71 Add(x,y,w);//添加双向边 72 Add(y,x,w); 73 } 74 } 75 76 void Prim() 77 { 78 int total = 0; 79 int ans = 0; 80 int now = 1; 81 for(int i = 2;i <=>) 82 { 83 dis[i] = INF; 84 } 85 86 for(int i = head[1];i;i=edges[i].next) 87 { 88 dis[edges[i].v] = min(dis[edges[i].v],edges[i].w); 89 }//更新所有与起点1相连的边并找到最小值 90 91 while(++total < n)//加入mst顶点数<图的顶点数即没找完,循环<> 92 { 93 int minn = INF; 94 vis[now] = 1; 95 for(int i = 1;i <=>)

96 { 97 if (! vis[i] && minn > dis[i])//找到一条最短边 98 { 99 minn = dis[i];100 now = i;101 }102 }103 ans += minn;//当前找到的最短距离加入结果距离变量中104 for(int i = head[now]; i ; i =edges[i].next)//松弛操作105 {106 int v = edges[i].v;107 if( ! vis[v]&& dis[v] > edges[i].w )108 {109 dis[v] = edges[i].w;110 }111 }112 }113 if(ans < INF)//找到解114 {115 cout<<ans<<endl;116 }117 else118 {119 cout<<"orz"<<endl;120 }121122 }123 int main()124 {125 Init();126 Prim();127 return 0;128 }</ans<<

View Code

传送门:Agri-Net

Original: https://www.cnblogs.com/ygsworld/p/11229055.html
Author: 回忆酿的甜
Title: 最小生成树-Prim算法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582160/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • cpp-变量

    1.枚举类型 枚举类型是用户自定义的类型,在定义时要列举出该枚举类型所有的数值。 定义格式如下: [enum] enumName {val1, val2, val3} 其中的通常为…

    Linux 2023年6月7日
    083
  • redis中save和bgsave区别

    SAVE 和 BGSAVE 两个命令都会调用 rdbSave 函数,但它们调用的方式各有不同: SAVE 直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。在…

    Linux 2023年5月28日
    061
  • C++ inline

    inline的坏处:若在一台内存有限的机器上,过度热衷inlining会造成程序体积太大,即使拥有虚拟内存,inline造成的代码膨胀也会导致额外的换页行为,降低指令高速缓存装置的…

    Linux 2023年6月7日
    094
  • 互斥锁与多线程间共享全局变量

    互斥锁 一、 代码展示 ① 没加锁(X) import threading num = 0 def write1(): global num i = 1 while i 运行结果 …

    Linux 2023年6月14日
    0100
  • 搭建zabbix 4.0

    安装zabbix的依赖包 下载zabbix源码包 数据库导入数据的命令格式:mysql ­u用户名 ­p密码 数据库名称 < 要导入的数据 此时的路径是在databases/…

    Linux 2023年6月8日
    0103
  • 程序员要知道的22个学习网站

    点击标题即可直达链接网址 GitHub是一个面向开源及私有软件项目的托管以及在线软件开发平台,用于存储、跟踪和协作软件项目,开发者能够上传自己的代码文件,并与其他开发者在开源项目上…

    Linux 2023年6月6日
    084
  • 记录一次shell脚本环境全局变量在函数内部生效问题

    背景 计划核对内网IP的使用情况,所以写了个小脚本扫描有哪些IP还在使用。执行脚本过程中发现函数中一直获取不到变量的值,排查后将结论记录下来。 问题现象 全局变量已配置,但在函数中…

    Linux 2023年5月27日
    070
  • 【Leetcode】120. 三角形最小路径和

    给定一个三角形 triangle ,找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。 &#x76F8;&#x90BB;&#x7684;&a…

    Linux 2023年6月6日
    0101
  • Redis16个常见使用场景

    目录 缓存 数据共享分布式 分布式锁 全局ID 计数器 限流 位统计 购物车 用户消息时间线timeline 消息队列 抽奖 点赞、签到、打卡 商品标签 商品筛选 用户关注、推荐模…

    Linux 2023年5月28日
    0107
  • RPA跨系统自动生成采购订单

    bash;gutter:true;1、从开发器启动机器人2、RPA登录友采云3、RPA根据筛选条件,导出采购订单4、RPA请并登录NC5、RPA把读取到的数据,逐个录入到NC系统中…

    Linux 2023年6月7日
    0124
  • mysql select语句查询流程是怎么样的

    mysql select查询的数据是查询内存里面,如果没有查询的数据没有在内存,就需要mysql的innodb引擎读取磁盘,将数据加载的内存后在读取。这就体现了,mysql查询大量…

    Linux 2023年6月8日
    085
  • [云原生]Kubernetes-Service详解(第7章)

    * – 一、Service介绍 – 二、Service类型 – 三、Service使用 + 3.1 实验环境准备 + 3.2 ClusterIP…

    Linux 2023年6月13日
    095
  • RHCSA阶段笔记

    命令终端字段含义介绍 [root@localhost ~]# 解释: root:当前登录系统用户名(root超级管理员) localhost :当前主机名 :当前用户所在目录( 为…

    Linux 2023年5月27日
    078
  • 关于NLog在.NET CORE下如何进行日志的持久化及通过邮件发送日志

    配置过程 安装NLog 通过Nuget进行集成(NuGet Gallery | NLog.Web.AspNetCore 4.14.0) 通过命令行安装 Install-Packag…

    Linux 2023年6月14日
    079
  • [SDR] GNU Radio 系列教程(二) —— 绘制第一个信号分析流程图

    1、前言 2、启动 GNU Radio 3、新增块 4、运行 本文视频 参考链接 1、前言 本文将介绍如何在 GNU Radio 中创建和运行第一个流程图。 2、启动 GNU Ra…

    Linux 2023年6月8日
    094
  • gcc/g++与动静库以及gdb

    gcc/g++ 程序转换为二进制 总共需要经过4个大步骤:1.预处理,2.编译,3.汇编,4.链接。 想要更深刻的了解它,可以通过Linux去深刻的了解他们。 先创建.C文件 并且…

    Linux 2023年6月13日
    079
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球