算法打卡第二天之——修复公路(并查集+Kruskal算法)

哟西!又到了晚间写题解的时间啦!!!今天呢,还是和昨天一样是并查集的算法呀!!!但是奥,小小的不一样,因为我们今天的题目还要用到Krukal算法,简单来说就是并查集的升级版题目呀!!!Emmmmm...开始之前,按照惯例,我们来稍(xue)微地讲一下,什么是Kruskal算法。

Krukal算法

克鲁斯卡尔算法是求连通网的最小生成树的另一种方法。与普里姆算法(Prim)不同,它的时间复杂度为O(eloge)(e为网中的边数),所以,适合于求边稀疏的网的最小生成树。克鲁斯卡尔(Kruskal)算法从另一途径求网的最小生成树。其基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),概述图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止

百度的解释就是如上。

简单点来讲就是要把所有的点联通到一起,同时求出最小的权值/大概是这样的一个意思吧...如果有什么问题的话还请各位在评论区指正。

大概的解释就是这样。至于并查集的话,就是合并+查找。Okay,知道了这两个基本的算法,我们就来解决一下今天的题目吧。其实这个是我昨天晚上写的,不过太晚了,没时间更新题解,所以就放到了今天。哦对了,并查集+Kruskal就变成了一个新的知识点,叫做最小生成树。/*快快快,这是重点哦,下次考试必考的!敲黑板.jpg*/

好啦,接下来,我们来看下题目。


A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。
题目描述
给出A地区的村庄数N,和公路数M,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)
输入输出格式
输入格式:
第1行两个正整数N,M
下面M行,每行3个正整数x, y, t,告诉你这条公路连着x,y两个村庄,在时间t时能修复完成这条公路。
输出格式:
如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1,否则输出最早什么时候任意两个村庄能够通车。
输入输出样例
输入样例:
4 4
1 2 6
1 3 4
1 4 5
4 2 3
输出样例:
5
说明
N<=1000,M<=100000
x<=N,y<=N,t<=100000

这就是题目了,乍一看是不是用我们的并查集板子就可以解决呢!!! 嘿嘿嘿,这可是最小生成树欸!如果只用一个并查集的板子,那肯定是解决不了问题的。因为他问到了一个最少,也就是说要出现比较,我们要找到最早的那个时间!让所有的村庄之前都产生联系!!!

那么这样的话,思路就出来啦!并查集+排序。按照题目的意思,他每一行会给我们三个数字,而这个排序不能只排其中的一个,而是要带着所有的数据一起排序,打包并进行排序。那是什么呢,就是结构体排序!不会结构体排序的小伙伴看这里哦!

struct road{
	int x,y,t;
}a[N];//首先我们要定义一个结构体,因为有三个数字所有我们的结构体里面应该是三个变量

bool cmp(road b,road c) {
  return b.t <c.t;
}//排序的话用这个函数进行比较,bool的话主要是简便,如果不想用bool类型的函数的话,
//使用int类型的函数也是可以的。
sort(a+1,a+m+1,cmp);
//在使用sort排序的时候不要忘记加头文件算法哦

对!就是这样的!排序加上并查集就可以解决这个问题啦!

欸嘿,最后啊,其实我还有个小小的问题留给大家思考,就是排序后的那个if条件是为什么。明白的小伙伴在评论区留言吧!!!好了,我要继续打游戏学习去了!

#include<bits/stdc++.h>
#define N 110000
using namespace std;

int parent[N],n,m;

struct road{
	int x,y,t;
}a[N];

bool cmp(road b,road c) {
  return b.t <c.t;
}
void init()
{
	for(int i=1;i<=n;i++)
	{
		parent[i]=i;
	}
}

int find(int x)
{
	if(parent[x]==x)
	{
		return x;
	}else {
		parent[x]=find(parent[x]);
		return parent[x];
	}
}

void uni(int x,int y)
{
	int dx=find(x);
	int dy=find(y);
	if(dx!=dy)
	{
		parent[dy]=dx;
		n--;
	}
}

int main()
{
	scanf("%d %d",&n,&m);
	init();
	for(int i=1;i<=m;i++){ 
		scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].t);
		
	}sort(a + 1, a + 1 + m, cmp);
	for(int i=1;i<=m;i++){
		uni(a[i].x,a[i].y);
		
		if(n==1){
			printf("%d\n",a[i].t);
			return 0;
		}
	}printf("-1\n");
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼 kilmo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值