最小生成树——Prim和Kruskal算法

news/2024/11/26 9:55:50/

这个算法和Prim用法是一致的,但是得到的方式却大不相同,Prim是找任意一个结点连着的最小的边,从而不断更新到达各个结点的最小花费。时间复杂度是:O(n*n),更适合稠密图;

而Kruskal算法是找到最小的边,看这条边的两点结点是否在相同的集合,如果是,说明形成回路,如果不是,及时更新两结点所在的集合,直至所有集合都是1。时间复杂度:O(eloge),更适合稀疏图。

Prim算法实现:

#include <iostream>
#include <algorithm>
using namespace std;const int N = 100;
const int INF = 1e7;int n,m;
int map[N][N],closest[N],lowcost[N];
bool flag[N];void Prim(int u){for(int i=1;i<=n;i++){if(i!=u){lowcost[i]=map[u][i];closest[i]=u;}flag[i]=false;}flag[u]=true;lowcost[u]=0;for(int i=1;i<=n;i++){int temp=INF,t=u;for(int j=1;j<=n;j++){if(!flag[j]&&temp>lowcost[j]){temp=lowcost[j];t=j;}}if(t==u){break;}flag[t]=true;for(int j=1;j<=n;j++){if(!flag[j]&&lowcost[j]>map[t][j]){lowcost[j]=map[t][j];closest[j]=t;}}}
}int main(void){cin>>n>>m;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){map[i][j]=INF;}}int u,v,w;while(m--){cin>>u>>v>>w;map[u][v]=w;map[v][u]=w;}int be;cout<<"请输入任意一个结点:";cin>>be;Prim(be);int sum=0;cout<<"数组lowcost的内容是:";for(int i=1;i<=n;i++){cout<<lowcost[i]<<" ";sum+=lowcost[i];}cout<<endl;cout<<"总的最少花费是:"; cout<<sum<<endl;return 0;
}

运行结果:

Kruskal算法

有两种方式,一种是可以用一个数组来描述他们是否在同一个集合中。

另一种是用并查集来看是否在同一个集合中。

先来看第一种:

#include <iostream>
#include <algorithm>
using namespace std;const int N = 100;int n,m;
int nodeset[N];		//各个结点所属集合 
struct Edge{int u,v,w;
}e[N*N];bool cmp(Edge x,Edge y){return x.w<y.w;
}int merge(int a,int b){int p=nodeset[a];int q=nodeset[b];if(p==q)return 0;else{for(int i=1;i<=n;i++){if(nodeset[i]==q){nodeset[i]=p;}}return 1;}
}int Kruskal(int n){int ans=0;for(int i=1;i<=m;i++){if(merge(e[i].u,e[i].v)){ans+=e[i].w;n--;if(n==1)return ans;}}return 0;
}int main(void){cin>>n>>m;for(int i=1;i<=n;i++){nodeset[i]=i;}for(int i=1;i<=m;i++){cin>>e[i].u>>e[i].v>>e[i].w;}sort(e+1,e+m+1,cmp);int ans=Kruskal(n);cout<<ans<<endl;return 0;
} 

运行结果:

第二种方式:

#include <iostream>
#include <algorithm>
using namespace std;const int N = 100;int n,m;
int f[N];		//各个结点所属集合 
struct Edge{int u,v,w;
}e[N*N];bool cmp(Edge x,Edge y){return x.w<y.w;
}int find(int x){if(x==f[x]){return x;}else{return find(f[x]);}
}int merge(int a,int b){int p=find(a);int q=find(b);if(p==q){return 0;}else if(p>q){f[p]=q;}else{f[q]=p;}return 1;
}int Kruskal(int n){int ans=0;for(int i=1;i<=m;i++){if(merge(e[i].u,e[i].v)){ans+=e[i].w;n--;if(n==1)return ans;}}return 0;
}int main(void){cin>>n>>m;for(int i=1;i<=n;i++){f[i]=i;}for(int i=1;i<=m;i++){cin>>e[i].u>>e[i].v>>e[i].w;}sort(e+1,e+m+1,cmp);int ans=Kruskal(n);cout<<ans<<endl;return 0;
} 

运行结果:


http://www.ppmy.cn/news/1550027.html

相关文章

算法编程题-寻找最近的回文数

算法编程题-寻找最近的回文数 原题描述思路简述代码实现复杂度分析参考 摘要&#xff1a;本文将对LeetCode 原题 564 寻找最近的回文数进行讲解&#xff0c;并且给出golang语言的实现&#xff0c;该实现通过了所有测试用例且执行用时超过100%的提交&#xff0c;最后给出相关的复…

非递归遍历二叉树(数据结构)

我的博客主页 非递归遍历二叉树 前序遍历&#xff08;迭代&#xff09;中序遍历&#xff08;迭代&#xff09;后续遍历&#xff08;迭代&#xff09; 二叉树的遍历方式有&#xff1a;前序遍历、中序遍历、后续遍历&#xff0c;层序遍历&#xff0c;而树的大部分情况下都是通过递…

YOLO 从标注到模型训练与检测

本篇文章将带你从数据标注开始&#xff0c;经过数据集转换和划分&#xff0c;最后训练 YOLO 模型并进行检测。包括必要的代码示例&#xff0c;以及路径和文件的详细说明&#xff0c;以帮助你完成整个流程。 1. 数据标注 首先&#xff0c;我们需要对目标检测的数据进行标注。这…

lvgl学习复选框部件和进度条部件(基于正点原子)

复选框部件&#xff08;lv_checkbox&#xff09; 复选框部件常用于选择某个内容的开启和关闭&#xff0c;可以理解为自带标签的开关。 复选框部件组成部分&#xff1a; 主体(LV_PART_MAIN) 勾选框(LV PART INDICATOR) 知识点1&#xff1a;创建复选框部件 lv_obj_t *check…

lambda的作用

lambda 的定义 lambda 是 Python 中用于创建匿名函数的关键字。匿名函数是一种没有名字的函数&#xff0c;通常用来定义简单的、一次性的函数。 lambda 的语法 lambda 参数列表: 表达式 参数列表: 函数的输入&#xff0c;可以有多个&#xff0c;用逗号分隔。表达式: 函数的…

前端高能组件库 Shadcn-UI

你是不是用 element-ui 或者 ant-design &#xff0c;然后&#xff0c;开发时常常遇到需要匹配设计稿时调样式的痛苦。 Shadcn-UI 结合tailwindcss &#xff0c;即可与让你享受组件同时随意的设置样式。 支持 VUE 官方地址&#xff1a;shadcn/ui 项目地址&#xff1a;https:…

极客时间《Redis核心技术与实战》开篇词 知识点总结

Redis 主要的数据持久化方式 RDB&#xff08;Redis Database Backup file&#xff09; RDB 是 Redis 提供的一种数据快照持久化方式&#xff0c;它会在指定的时间间隔内生成数据集的时间点快照&#xff0c;并将这些快照保存到磁盘上的一个 RDB 文件中。RDB 文件是一个压缩的二…

Docker 配置 HTTP 和 HTTPS 网络代理

前言 在内网环境中&#xff0c;为了实现全局代理上网&#xff0c;Linux 系统通常通过修改 .bashrc 或 /etc/profile 等文件&#xff0c;设置 HTTP 和 HTTPS 代理。这种方式可以为大多数应用提供代理支持&#xff0c;但 Docker 并不会自动读取系统的环境变量&#xff0c;因此需…