当前位置: 首页 > news >正文

数据结构-图的最小生成树

最小生成树介绍

最小生成树(Minimum Cost Spanning Tree)是代价最小的连通网的生成树,即该生成树上的边的权值和最小

最小生成树的性质:

必须使用且仅使用连通网中的n-1条边来联结网络中的n个顶点;

不能使用产生回路的边;

各边上的权值的总和达到最小

最小生成树在连通网场景中应用广泛,例如

在n个城市之间建立通信网络,如何建立成本最小的网络

在n个城市之间建立公路网络,如何建立成本最小的网络

应用场景:“村村通”,我国系统工程,全国行政村互通:公路、电力、生活和饮用水、电话网、有线电视网、互联网等等

村村通公路,村村通水气电,村村通5G,村村通宽带

2025年全国基本实现村村通

Prim算法

普里姆(Prim)算法设计

假设N=(V,E)是连通网

TE是N上最小生成树中边的集合

  1.U={u0},(u0ÎV), TE={}

  2.在所有uÎU,vÎV-U的边(u,v)ÎE中找一条代价最小的边(u,v0)并入集合TE,同时v0并入U

  3.重复2,直到U=V

算法示例

        普里姆(Prim)算法设计思想:每次找到的最小权值边,一头属于已选顶点U,一头属于未选顶点V-U设置一个辅助数组closedge,用于保存未选顶点的最小权值边closedge,而且这条边的另一个点必然输入已选顶点

推导流程

普里姆(Prim)算法分析

从算法看出,算法只是和顶点数量相关,与边无关

时间复杂度为O(n2)

普里姆适用于边稠密的网,

当一个通信网的点数量少但边数量多,则用普里姆

参考设计代码

class Edge {
public:string begin;string end;int weight;
};
//!!!!!!!!普里姆算法!!!!!!!!!void Prim() {Edge *q = new Edge[l];string s;cin >> s;int start = find(s);for (int i = 0; i < l; i++) {arr[i][start] = 0;}int k = 0;int next;int remain = l - 1;while (remain > 0) {arr[start][l] = 1;int min = 0xffff;for (int i = 0; i < l; i++) {if (arr[i][l] == 1) {for (int j = 0; j < l; j++) {if (arr[i][j] < min && arr[i][j] != 0) {min = arr[i][j];start = i;next = j;}}}}q[k].begin = str[start];q[k].end = str[next];q[k].weight = arr[start][next];sum += arr[start][next];k++;for (int i = 0; i < l; i++) {arr[i][next] = 0;}remain--;start = next;}cout << sum << endl;cout << "prim:" << endl;for (int i = 0; i < k; i++)cout << q[i].begin << ' ' << q[i].end << ' ' << q[i].weight << endl;}

 

Kruskal算法

最小生成树生成算法——克鲁斯卡尔(Kruskal)算法

假设G=(V,E)是连通网,设非连通图T={V,{}},图中每个顶点自成一个连通分量

1.在E中找一条代价最小,且其两个顶点分别依附不同的连通分量的边,将其加入T中

2.重复1,直到T中所有顶点都在同一连通分量上

算法示例

算法设计

 克鲁斯卡尔算法设计用选择排序算法,只需要即找出n-1条符合要求的边

难点:如何判断一条边属于两个不同的连通分量

设计辅助数组Belong[n],其中Belong[i]初始为-1,表示顶点i未选

当选中一条边,查看这条边的两个顶点i和j

如果Belong[i]和Belong[j]都是-1,则生成新分量编号并设Belong[i]和Belong[j]

如果Belong[i]或Belong[j]是-1,则生成新分量编号并设Belong[i]或Belong[j]

如果Belong[i]或Belong[j]都不是-1,则说明两个顶点已选

如果Belong[i]==Belong[j],则说明同属一个分量,放弃

如果Belong[i]<>Belong[j],则说明分属不同分量,选择这条边并把两个分量合并,即更改相关分量的Belong值 

 算法分析

算法只是和边数量相关,因此适用于点稠密的网

时间复杂度为O(eloge)

当一个通信网的边数量少但点数量多,则适用

参考代码 

//克鲁斯卡尔算法执行结点
class edge {
public:int begin;int end;int weight;
};//!!!!!!!克鲁斯卡尔算法!!!!!void Kurskal() {for (int i = 0; i < l; i++)flag[i] = 0;cout << "kruskal:" << endl;//将所获得边集数组进行排序for (int i = 0; i < t; i++)for (int j = 0; j < t - i - 1; j++) {if (e[j].weight > e[j + 1].weight)swap(e[j], e[j + 1]);}for (int i = 0; i < l; i++) {int o = find(e[i].begin);int p = find(e[i].end);if (o != p) {flag[o] = p;cout << str[e[i].begin] << ' ' << str[e[i].end] << ' ' << e[i].weight << endl;}}}

 

完整代码(仅供参考)
#include<iostream>
#include<queue>#define nu 0xffff;
using namespace std;class node {
public:int info;node *next;node() {next = nullptr;}
};class point {
public:int data;node *head;point() {head = nullptr;}
};//克鲁斯卡尔算法执行结点
class edge {
public:int begin;int end;int weight;
};class Edge {
public:string begin;string end;int weight;
};class graph {
private:int l, t;int **arr;string *str;int *flag;edge *e;int sum = 0;point *a;int n, m;
public:graph() {Create();}//邻接矩阵存储void Create() {cin >> l;str = new string[l];flag = new int[l];arr = new int *[l + 1];for (int i = 0; i < l; i++) {flag[i] = 0;arr[i] = new int[l];}for (int i = 0; i < l; i++)for (int j = 0; j < l; j++)arr[i][j] = nu;for (int i = 0; i < l; i++)cin >> str[i];cin >> t;for (int i = 0; i < t; i++) {string o, p;int num;cin >> o >> p >> num;int oo = find(o), pp = find(p);arr[oo][pp] = arr[pp][oo] = num;e[i].begin = oo;e[i].end = pp;e[i].weight = num;}for (int i = 0; i < l; i++) {for (int j = 0; j < l; j++)cout << arr[i][j] << ' ';cout << endl;}}//克鲁斯卡尔算法int find(int i) {while (flag[i] > 0)i = flag[i];return i;}int find(const string &ss) {for (int i = 0; i < l; i++)if (str[i] == ss)return i;return -1;}//!!!!!!!克鲁斯卡尔算法!!!!!void Kurskal() {for (int i = 0; i < l; i++)flag[i] = 0;cout << "kruskal:" << endl;//将所获得边集数组进行排序for (int i = 0; i < t; i++)for (int j = 0; j < t - i - 1; j++) {if (e[j].weight > e[j + 1].weight)swap(e[j], e[j + 1]);}for (int i = 0; i < l; i++) {int o = find(e[i].begin);int p = find(e[i].end);if (o != p) {flag[o] = p;cout << str[e[i].begin] << ' ' << str[e[i].end] << ' ' << e[i].weight << endl;}}}//!!!!!!!!普里姆算法!!!!!!!!!void Prim() {Edge *q = new Edge[l];string s;cin >> s;int start = find(s);for (int i = 0; i < l; i++) {arr[i][start] = 0;}int k = 0;int next;int remain = l - 1;while (remain > 0) {arr[start][l] = 1;int min = 0xffff;for (int i = 0; i < l; i++) {if (arr[i][l] == 1) {for (int j = 0; j < l; j++) {if (arr[i][j] < min && arr[i][j] != 0) {min = arr[i][j];start = i;next = j;}}}}q[k].begin = str[start];q[k].end = str[next];q[k].weight = arr[start][next];sum += arr[start][next];k++;for (int i = 0; i < l; i++) {arr[i][next] = 0;}remain--;start = next;}cout << sum << endl;cout << "prim:" << endl;for (int i = 0; i < k; i++)cout << q[i].begin << ' ' << q[i].end << ' ' << q[i].weight << endl;}};

相关文章:

  • 串口通讯(串行接口通讯)
  • VSCode 设置代理
  • 【2024美国大学生数学建模竞赛】2024美赛C题网球运动中的势头,网球教练4.0没人比我更懂这个题了!!!
  • 做好测试用例的分析 ? 是做好软件测试的必要步骤。
  • android开发---简单购物商城(JAVA) (一)
  • 18- OpenCV:基于距离变换与分水岭的图像分割
  • 《HTML 简易速速上手小册》第9章:HTML5 新特性(2024 最新版)
  • Jasperreport 生成 PDF之省纸模式
  • 探索Gin框架:Golang使用Gin完成文件上传
  • 深度学习如何入门?
  • RabbitMQ面试
  • 【云原生kubernetes系列】---亲和与反亲和
  • 《区块链简易速速上手小册》第7章:区块链在其他行业的应用(2024 最新版)
  • leetcode189.轮转数组|超简单易于理解方法
  • Elasticsearch:如何为 Elastic Stack 配置 AI Assistant
  • python3.6+scrapy+mysql 爬虫实战
  • .pyc 想到的一些问题
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 07.Android之多媒体问题
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • ComponentOne 2017 V2版本正式发布
  • JS数组方法汇总
  • MYSQL 的 IF 函数
  • Nacos系列:Nacos的Java SDK使用
  • tweak 支持第三方库
  • vue脚手架vue-cli
  • webpack入门学习手记(二)
  • 从输入URL到页面加载发生了什么
  • 代理模式
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 观察者模式实现非直接耦合
  • 悄悄地说一个bug
  • 微信公众号开发小记——5.python微信红包
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • ​决定德拉瓦州地区版图的关键历史事件
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (一)插入排序
  • (转)一些感悟
  • (转载)Linux网络编程入门
  • (轉)JSON.stringify 语法实例讲解
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • @RequestParam详解
  • [120_移动开发Android]008_android开发之Pull操作xml文件
  • [20171106]配置客户端连接注意.txt
  • [Android实例] 保持屏幕长亮的两种方法 [转]
  • [C++]18:set和map的使用