08-图7 公路村村通 (30分)(C语言实现)(数据结构)

2023-11-28 18:48

本文主要是介绍08-图7 公路村村通 (30分)(C语言实现)(数据结构),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

我们首先需要定义结构体以及其他一些定义

#include<stdio.h>
#define Max 1000
typedef struct
{int x,y;int cost;
}city;
typedef struct//堆
{city data[3005];int size;
}Minheap;
Minheap minh;
int n,m;
int path[1005];//用来存放父结点的下标(集合操作),每个数组下标存放父亲结点,为根节点则为0

函数的声明

void Kruskal();
city del(Minheap &h);

首先看一下堆的操作

void init(Minheap &h)//初始化堆
{h.size=0;h.data[0].cost=-1;
}
void insert(Minheap &h,city a)//堆的插入操作
{int i=++h.size;//传入一个容量+1for(;i>0&&a.cost<h.data[i/2].cost;i/=2){h.data[i]=h.data[i/2];}h.data[i]=a;
}
city del(Minheap &h)//最小堆中的删除操作
{city min=h.data[1];/*我们是从数组下标为1开始存入数据的,所以此时为最小值*/city last=h.data[h.size--];if(h.size==0) return min;int i=2;for(;i<=h.size;){if(h.data[i].cost>h.data[i+1].cost&&i<h.size)/*在堆中,父结点值肯定比子树要小,但是左右子树就不确定了*/i++;if(h.data[i].cost<last.cost) //从子树找更小的值代替根节点,再从子树的子树找更小的代替子树{h.data[i/2]=h.data[i];i*=2;}else break;}h.data[i/2]=last;return min;
}

判断是否属于一个集合

int judgeroot(city a){while(path[a.x]!=0) {a.x=path[a.x];}         //进行循环,直到找到根while(path[a.y]!=0) {a.y=path[a.y];}if(a.x==a.y) return 0;else {path[a.x]=a.y;return 1;}
}

核心算法

void Kruskal()//算法
{int v=0,mincost=0;while(v!=n-1&&minh.size!=0)//有公路数{city a=del(minh);if(judgeroot(a))//判断是否属于同一个集合,如果属于同一个集合,错误{v++;//连通数加1mincost+=a.cost;//加上这条道路的花费}}	if(v!=n-1)  printf("-1\n");//没有连通,中途操作没有执行完else printf("%d\n",mincost);//打印最小花费
}

主函数

int main(){city a;init(minh);scanf("%d%d",&n,&m);//输入城镇数目和候选道路数for(int i=0;i<m;i++){scanf("%d%d%d",&a.x,&a.y,&a.cost);//输入道路号和代价insert(minh,a);//插入堆中}Kruskal(); //算法
} 

文章总代码如下

#include<stdio.h>
#define Max 1000
typedef struct
{int x,y;int cost;
}city;
typedef struct//堆
{city data[3005];int size;
}Minheap;
Minheap minh;
int n,m;
int path[1005];//用来存放父结点的下标(集合操作)void Kruskal();
city del(Minheap &h);void init(Minheap &h)//初始化堆
{h.size=0;h.data[0].cost=-1;
}
void insert(Minheap &h,city a)//堆的插入操作
{int i=++h.size;//传入一个容量+1for(;i>0&&a.cost<h.data[i/2].cost;i/=2){h.data[i]=h.data[i/2];}h.data[i]=a;
}
int judgeroot(city a){while(path[a.x]!=0) {a.x=path[a.x];}         //进行循环,直到找到根while(path[a.y]!=0) {a.y=path[a.y];}if(a.x==a.y) return 0;else {path[a.x]=a.y;return 1;}
}
void Kruskal()//算法
{int v=0,mincost=0;while(v!=n-1&&minh.size!=0)//有公路数{city a=del(minh);if(judgeroot(a))//判断是否属于同一个集合,如果属于同一个集合,错误{v++;//连通数加1mincost+=a.cost;//加上这条道路的花费}}	if(v!=n-1)  printf("-1\n");//没有连通,中途操作没有执行完else printf("%d\n",mincost);//打印最小花费
}
city del(Minheap &h)//最小堆中的删除操作
{city min=h.data[1];/*我们是从数组下标为1开始存入数据的,所以此时为最小值*/city last=h.data[h.size--];if(h.size==0) return min;int i=2;for(;i<=h.size;){if(h.data[i].cost>h.data[i+1].cost&&i<h.size)/*在堆中,父结点值肯定比子树要小,但是左右子树就不确定了*/i++;if(h.data[i].cost<last.cost) //从子树找更小的值代替根节点,再从子树的子树找更小的代替子树{h.data[i/2]=h.data[i];i*=2;}else break;}h.data[i/2]=last;return min;
}int main(){city a;init(minh);scanf("%d%d",&n,&m);//输入城镇数目和候选道路数for(int i=0;i<m;i++){scanf("%d%d%d",&a.x,&a.y,&a.cost);//输入道路号和代价insert(minh,a);//插入堆中}Kruskal(); //算法
} 

对了还要提一点,在PTA中c可能编译不成功,不知道为啥,有解决办法的同学请教教我,但是用c++编译就可以成功了。

这篇关于08-图7 公路村村通 (30分)(C语言实现)(数据结构)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/430110

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl