首页 > 其他分享 >最小生成树

最小生成树

时间:2024-01-24 10:11:40浏览次数:21  
标签:int 最小 生成 high low key ELEMENT

生成树是指无向图中连通且n个顶点n - 1条边的树。最小生成树就是构造连通图的最小代价的生成树。

最小瓶颈树就是在树上最大的边权值在所有生成树中最小。那么有一个定理,最小生成树就是最小瓶颈树,但最小瓶颈树不一定是最小生成树。

解决最小生成树有两种算法分别为:Prim(不常用)和Kruskal(常用)

两种算法分别需要不同的数据结构,分别为Prim(小根堆)和Kruskal(并查集)

两种算法的角度不同:Prim是从顶点考虑边,而Kruskal是从边考虑顶点

当然两种算法的本质是:贪心策略

 但Kruskal是不需要建图的就可以求出最小权值,而Prim算法需要建图

但Prim算法可以优化成在点比边少的情况下,比Kruskal快

洛谷测试链接

Kruskal算法实现(借助并查集,从边的角度建树)

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 100001//最大集合个数 

typedef struct {
	int f;
	int t;
	int w;	
}ELEMENT;

void quickSort(ELEMENT *a, int low, int high);//快排的接口 
void swap(ELEMENT *a, int low, int high);//交换a[low]和a[high]的值 
int* partition(ELEMENT *a, int low, int high, ELEMENT key);//把a中low到high的数按照key分类,小于key的在左边,等于key的在中间,大于key的在右边

ELEMENT edge[2 * N + 1];//存放边的数组,因为边最多有2 * 10 ^ 5题目给出的 
int n;//集合的个数 
int m;//操作的次数 
int f[N];//f[i]表示元素i的下一个元素是谁,如果f[i]等于i那么f[i]就是整个集合的代表元素  

//查询元素x在那个集合里面 
int find(int x) {
	if (x != f[x]) {//只要不是集合的代表元素 
		f[x] = find(f[x]);//路径压缩 
	}
	
	return f[x];//返回集合的代表元素,向下传递的过程 
}
 
//判断元素a和b是不是在同一个集合当中 
bool isSameSet(int a, int b) {
	return find(a) == find(b);//判断代表两个集合的代表元素相同不相同就可以了 
}

//合并两个集合 
void unionSet(int a, int b) {
	f[find(a)] = find(b);//直接左边的合并到右边,对应着指向根节点 
}

int main(int argc, char* argv[])
{
	sc("%d %d", &n, &m);
	
	//初始化集合 
	for (int i = 1; i <= n; i++) {
		f[i] = i;
	}
	
	for (int i = 0; i < m; i++)  {//读入边和对应的权重 
		sc("%d%d%d", &edge[i].f, &edge[i].t, &edge[i].w);
	}
	
	quickSort(edge, 0, m - 1);//随机快速排序从小到大按照边的权重排序 
	
	int cnt = 0;//统计选取边的数量 
	int ans = 0;//每条边的权重和即答案 
	
	for (int i = 0; i < m && cnt < n - 1; i++) {//遍历完整个边的数组或者选取边的数量已经成了最小生成树了,那么跳出循环,不用再遍历了 
		if (!isSameSet(edge[i].f, find(edge[i].t))) {//如果选取的边不会和之前选取的边构成环,那么就可以选取这条边 
			ans += edge[i].w;//选取了这条边,所以加上对应的权重 
			cnt++;//选取边的数量加一 
			unionSet(edge[i].f, edge[i].t);//放入选取边的集合 
		}	
	}
	 
	if (cnt == n - 1) {//如果选取的边的个数等于n - 1条,代表有最小生成树,输出权重和 
		pr("%d", ans);
	}
	else {//没有最小生成树,输出orz 
		pr("orz");
	}
	
	return 0;
}

void quickSort(ELEMENT *a, int low, int high)
{
	int *p = NULL;//存储等于基准值的左右边界 
	
	if ( low >= high) {//如果只有一个值不用排序就直接结束排序 
		return ;
	}
	
	p = partition(a, low, high, a[low + rand() % (high - low + 1)]);//p指向等于基准值区间左右边界 
	quickSort(a, low, p[0] - 1);//只排小于基准值的部分 
	quickSort(a, p[1] + 1, high);//只排大于基准值的部分
	free(p);//释放掉开辟的空间 
}
void swap(ELEMENT *a, int low, int high)
{
	ELEMENT t = {0};
	
	t = a[low];
	a[low] = a[high];
	a[high] = t;
}
int* partition(ELEMENT *a, int low, int high, ELEMENT key)
{
	int l = low;//代表等于key区间的左边界,或者是小于区间的下一个数  
	int r = high;//代表等于key区间的右边界,或者是大于区间的下一个数  
	int i = low;//从头开始遍历 
	
	while(i <= r) {//只要没有到大于区间 
		if (a[i].w < key.w) {//下标i的数小于基准值,放在左边界里面 
			swap(a, l++, i++);//把左边界的后一个数和下标i的值交换,然后左区间扩张,然后去看下一个数 
		}
		else  if (a[i].w > key.w){//下标i的数大于基准值,放在右边界里面 
			swap(a, r--, i);//把右边界的前一个数和下标i的值做交换,然后右区间扩张,但i不能动,因为当前i的值还没有访问过 
		}
		else {//下标i的数等于基准值,放在左右边界之间 
			i++;//直接加1
		}
	} 
	int *p = (int *)malloc(sizeof(int ) * 2);//存放等于区间的左右边界 
	p[0] = l;//等于区间左边界就是l
	p[1] = r;//等于区间左边界就是r
	return p;//返回等于key区间的左右边界 
}

 时间复杂度是O(m * logm) + O(n) + O(m),m是边的数量,n是节点的数量。

标签:int,最小,生成,high,low,key,ELEMENT
From: https://www.cnblogs.com/lwj1239/p/17982040

相关文章

  • python requirements.txt的生成和安装
     一、在python代码迁移环境时需要保证各个依赖包版本一致以避免出现一些问题,批量安装依赖包方法如下:1)生成requirement.txt在服务器中切换到项目路径下,执行以下命令:piplist--format=freeze>requirements.txt所生成的requirement.txt中包含依赖包名和版本2)批量安装依赖......
  • .NET集成IdGenerator生成分布式全局唯一ID
    前言生成分布式唯一ID的方式有很多种如常见的有UUID、Snowflake(雪花算法)、数据库自增ID、Redis等等,今天我们来讲讲.NET集成IdGenerator生成分布式全局唯一ID。分布式ID是什么?分布式ID是一种在分布式系统中生成唯一标识符的方法,用于解决多个节点之间标识符重复或性能问题。分布......
  • 生成方向论文速览
    High-ResolutionImageSynthesiswithLatentDiffusionModels主要思想:基于像素空间的扩散模型训练需要消耗巨量资源。作者认为模型在训练的时候会经过两个阶段,前一阶段是语义的压缩和理解,是模型比较重要的,而后一阶段是感知理解和压缩,是人无法感受到的。通过提前训练一个encod......
  • 手型机器人、灵巧手机器人:交互感知-行为提取-意图理解-技能生成-运动映射-灵巧操作”
    灵巧手机器人,灵巧精准操作的手型机器人,最有名的应该就是Google的Deepmind推出的可以玩魔方的手型机器人了,如下图:相关资料:https://baijiahao.baidu.com/s?id=1647601517185392390&wfr=spider&for=pchttps://m.thepaper.cn/baijiahao_4728005地址:http://www.ia.cas.cn/kygz......
  • asp使用ItextSharp生成Pdf
    1.使用ItextSharp生成Pdf应用场景:将用户所填写的数据根据业务场景填入到pdf模板中并生成新的pdf。操作步骤如下:1.1.使用word制作模板制作word模板然后转成pdf,使用福昕或者其他pdf编辑器在需要填充数据的地方添加文本域(我这里使用的是破解版的福昕)。1.2.设置变量将需要填......
  • 便捷生成官方证件照:Passport Maker AI 为你提供完美解决方案
    引言在申请护照、签证或身份证时,我们经常需要一张符合规定的照片。PassportMakerAI是一款在线工具,旨在帮助用户轻松创建符合130多个国家尺寸和背景要求的护照、签证和身份证照片。本文将深入介绍PassportMakerAI的功能和作用。PassportMakerAI的作用1.轻松创建官方证......
  • 22. 括号生成
    1.题目介绍数字n代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。示例1:输入:n=3输出:["((()))","(()())","(())()","()(())","()()()"]示例2:输入:n=1输出:["()"]提示:1<=n<=82.题解2.1暴力枚举思路我们利用递归枚举出n对......
  • templeetcode 22.括号生成
    leetcode22.括号生成第二十二题:括号生成1.回溯:publicList<String>generateParenthesis(intn){List<String>ans=newArrayList<String>();backtrack(ans,newStringBuilder(),0,0,n);returnans;}publicvoidbackt......
  • Oracle AWR报告自动生成异常
    监控平台收集不到wrh$_tablespace_space_usage表数据。awr报告没有任何快照信息。alter日志发现报错:SuspendingMMONslaveactionkewrmafsa_for82800seconds MMON进程trace文件报错如下:UnabletoscheduleaMMONslaveat:AutoFlushMain1Slaveactionhasbeen......
  • 基于信号量的环形队列的生成消费模型(万字长文详解)
    linux线程之信号量POSIX信号量阻塞队列的缺陷==这是一个我们自己的实现阻塞队列!==classBlockQueue{public:BlockQueue(constint&maxcap=gmaxcap):maxcap_(maxcap){pthread_mutex_init(&mutex_,nullptr);......