【算法每日一练]-图论(保姆级教程篇7 最小生成树 ,并查集模板篇)#村村通 #最小生成树

news2024/12/23 1:49:08

目录

题目:村村通

并查集 

题目:最小生成树

kruskal算法

prim算法


        

先引入问题:

要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树

说白了就是将此图连通起来的最小代价。

        

对于一个有N个点的图,边一定是大于等于N-1条的。图的最小生成树,就是在这些边中选择N-1条出来,连接所有的N个点。这N-1条边的边权之和是所有方案中最小的

有两种算法:prim和kruskal

前者适合稠密图,后者适合稀疏图(不然炸你内存)

        

        

要先说并查集才行

题目:村村通

        

并查集 

【并查集思想】:是集合。一个是并操作(建树),一个是查操作(查树)。并操作是将一个集合的树变成另一个集合树的子树。

        
我们只需要建和原图等价的并查树即可,根本不用建原图
查操作是从该元素开始查找父节点直到找到根节点看看是否相同

        
1,初始化每个点的父亲为自身
2,并操作:(建边)合并两个集合的树根(祖宗)(查的过程中并路径压缩)
3,查操作:最后查找有几个祖宗即可

#include <bits/stdc++.h>              
using namespace std;
int fa[1000001], n, m, x, y;
int find(int x)
//找到祖先后并修改中间点的fa(路径压缩使更快的查到祖宗,
//其实就是对树进行优化,减少了树的深度,效果是将多代变成一代) 
{
    if(x!=fa[x]) fa[x]=find(fa[x]);
//自己不是祖宗,直接更新成亲爹的祖宗号
//但是如果是dp,那就要先保存原亲爹号,不然你就找不到爹了(路径压缩的代价)
    return fa[x];//返回祖先 
}
void unity(int x, int y)
{
    int f1=find(x);//如果x和y本来就在同一个集合完全 不影响
    int f2=find(y);
    fa[f1]=f2;//合并树根 
}
int main()
{
	while(true)
	{
		int ans=0;
		cin>>n>>m;
		if(n==0) return 0;
	    for(int i=1; i<=n; i++){
	    	fa[i]=i;//先初始化成节点
		}
	    for(int i=1; i<=m; i++){
	    	scanf("%d %d", &x, &y);//合并<x,y>能到的地方
	        unity(x,y);//建边,建树
		}
	    for(int i=1; i<=n; i++){//一共有几个祖宗
	    	if(find(i)==i) ans++;
		}
		printf("%d\n", ans-1);//共需修ans-1条路即可
	}
    return 0;
}

         

         

题目:最小生成树

         

kruskal算法

【kruskal】:贪心的每次取最小权值的边进行合并(只要不构成环),当恰好合并了n-1条边时候就是最小生成树。只要小于就不是,此图也不连通
可以使用并查集来实现合并和不构成环

                
kruskal甚至不需要建图,但是如果是完全图的话,存边容易MLE,这时候就要prim

#include<bits/stdc++.h>
using namespace std;
int f;
struct Edge{ int u,v,w; }e[200005];
int fa[5005],n,m,ans,cnt;

bool cmp(Edge a,Edge b){ return a.w<b.w;}

int find(int x)
{
    if(x!=fa[x]) fa[x]=find(fa[x]);
    return fa[x];//返回祖先 
}

void kruskal()
{
    sort(e+1,e+1+m,cmp);//将边的权值排序
    for(int i=1;i<=m;i++)
    {
        int fu=find(e[i].u), fv=find(e[i].v);
        if(fu==fv) continue;  //若出现两个点已经联通了,则说明这一条边不需要了
        ans+=e[i].w; //将此边权计入答案
        fa[fv]=fu; //合并操作
        if(++cnt==n-1)//如果边数恰好为n-1,则说明最小生成树已经建成
        {
            f=1;break;
        }
    }
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) fa[i]=i;//初始化并查集节点
    for(int i=1;i<=m;i++)
    {
        scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
    }
    kruskal();
    if(f==1)printf("%d",ans);
    else cout<<"orz";//不连通
    return 0;
}

         

prim算法

【prim算法】:prim算法基于贪心,我们每次总是选出一个离生成树距离最小的点去加入生成树,最后实现最小生成树(不做证明,理解思想即可)

每次都最小生成数和dijkstra思想很像,都是从小图开始,每次都从周围合并一个最小的点然后不断扩大,所以长得也很像,感觉完全一样啊

#include <bits/stdc++.h>
using namespace std;
int k,n,m,cnt,sum;
int head[5005],dis[5005],vis[5005];
typedef pair <int,int> pii;
struct Edge{ int v,w,next;}e[400005];

void add(int u,int v,int w){e[++k]=(Edge){v,w,head[u]};head[u]=k;}

void prim()
{
	priority_queue <pii,vector<pii>,greater<pii> > q;
	memset(dis,0x3f,sizeof(dis));
    dis[1]=0;//dis是周围点到集合的最小距离
    q.push(make_pair(0,1));
    while(!q.empty()&&cnt<n)//cnt是已经加入的点数
    {
        int d=q.top().first,u=q.top().second;//取出周围最小dis的点
        q.pop();
        if(vis[u]) continue;
        cnt++;
        sum+=d;
        vis[u]=1;//标记此点已经加入
	    for(i=head[u];i;i=e[i].next){
	        int ve=e[i].v,vw=e[i].w;//到集合最小距离就是权值
	        if(vw<dis[ve])//如果变小就更新入队,以便获取最小的点
	            dis[ve]=vw,q.push(make_pair(dis[ve],ve));
	    }
    }
}

int main()
{
	int u,v,w;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,w);
    }
    prim();
    if (cnt==n)printf("%d",sum);
    else printf("orz");//如果小于n说明不连通
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1263043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序nodejs+vue+uniapp视力保养眼镜店连锁预约系统

作为一个视力保养连锁预约的网络系统&#xff0c;数据流量是非常大的&#xff0c;所以系统的设计必须满足使用方便&#xff0c;操作灵活的要求。所以在设计视力保养连锁预约系统应达到以下目标&#xff1a; &#xff08;1&#xff09;界面要美观友好&#xff0c;检索要快捷简易…

【密码学】【安全多方计算】浅析隐私求交PSI

文章目录 隐私求交的定义隐私求交方案介绍1. 基于DH的PSI方案2. 基于OT的PSI方案3.基于OPRF的PSI方案 总结 隐私求交的定义 隐私集合求交使得持有数据参与方通过计算得到集合的交集数据&#xff0c;而不泄露任何交集以外的数据信息。 隐私求交方案介绍 1. 基于DH的PSI方案 …

漏电保护器工作原理

漏电保护器 漏电保护器是低压线路中最常用的保护器之一&#xff0c;简称漏保&#xff0c;又称漏电开关或漏电断路器。漏电保护器除了具有空开的所有保护功能外&#xff0c;还具备漏电保护功能。 需要了解 一根通电导线可以产生磁场&#xff0c;磁场与电流方向遵循右手螺旋关…

[Linux] Linux入门必备的基本指令(不全你打我)

一:ls指令 语法 &#xff1a; ls [选项] [目录或文件] 功能 &#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 ls不带选项就是显示当前目录下存在的子目录和文件 常用选项: (1). ls -l 功能: 列出…

Vue3-toRaw 和 markRaw 函数

Vue3-toRaw 和 markRaw 函数 toRaw(转换为原始)&#xff1a;将响应式对象转换为普通对象&#xff0c;只适用于 reactive 生成的响应式对象。markRaw(标记为原始)&#xff1a;标记某个对象&#xff0c;让这个对象永远都不具备响应式。一些集成的第三方库&#xff0c;会有大量的…

【解决方案】基于边缘计算技术的安科瑞综合管廊能效管理平台

平台背景 综合管廊一般是建于城市地下用于容纳两类及以上城市工程管线的构筑物及附属设施&#xff0c;将电力、自来水、热力、煤气、电信、网络等市政公用管线根据规划要求集中敷设在同一个构建物内&#xff0c;实施统一设计、施工、管理的市政公用隧道空间&#xff0c;并且还…

短剧小程序开发,短剧视频火热程序

近期&#xff0c;短剧以其独特的魅力在快节奏、忙碌的生活中迅速走红。在匆忙等待食物间隙&#xff0c;或想放松身心的片刻&#xff0c;短句成为人们难得的片刻宁静。 短剧小程序应运而生&#xff0c;在这个小巧的应用中&#xff0c;汇聚了多部丰富多样的正版短剧&#xff0c;为…

ELK---filebeat日志收集工具

filebeat也是日志收集工具&#xff0c;和logstash相同。 filebeat的特点 filebeat是一个轻量级的日志收集工具&#xff0c;所使用的系统资源比logstash部署和启动时使用的资源小的多。 filebeat可以运行在非java环境&#xff0c;他可以代替logstash在非java环境上收集日志 缺…

电脑如何定时关机?

电脑如何定时关机&#xff1f;我承认自己是个相当粗心的人&#xff0c;尤其是在急于离开时经常会忘记关闭电脑&#xff0c;结果就是电量耗尽&#xff0c;导致电脑自动关机。而且&#xff0c;在我使用电脑的时候&#xff0c;经常需要进行软件下载、更新等任务。如果我一直坐等任…

ArkTS-共享元素转场动画

共享元素转场动画 在不同页面间&#xff0c;有使用相同的元素&#xff08;例如同一幅图&#xff09;的场景&#xff0c;可以使用共享元素转场动画衔接。为了突出不同页面间相同元素的关联性&#xff0c;可为它们添加共享元素转场动画。如果相同元素在不同页面间的大小有明显差异…

零信任安全:远程浏览器隔离(RBI)的重要性

引言 在当今数字化时代&#xff0c;网络安全已成为个人和企业关注的焦点。随着网络攻击和恶意软件的不断增加&#xff0c;远程浏览器隔离(RBI)SAAS系统变得至关重要。本文将深入探讨远程浏览器隔离系统的重要性&#xff0c;以及它如何帮助用户保护其网络免受恶意软件和网络攻击…

【傻瓜级JS-DLL-WINCC-PLC交互】1.C#用windows窗体控件创建.net控件

思路 JS-DLL-WINCC-PLC之间进行交互&#xff0c;思路&#xff0c;先用Visual Studio创建一个C#的DLL控件&#xff0c;然后这个控件里面嵌入浏览器组件&#xff0c;实现JS与DLL通信&#xff0c;然后DLL放入到WINCC里面的图形编辑器中&#xff0c;实现DLL与WINCC的通信。然后PLC与…

台式机加独显引发的故事

弄到一块NVIDIA1660显卡&#xff0c;想要加到台式机&#xff0c;枯树逢春&#xff1b;中间引发不少事情&#xff0c;记录下来共勉 1.台式机插入显卡 1&#xff09;拆开主机后部的接口片 2&#xff09;显卡插入显卡巢&#xff0c;很内存条结构类似&#xff08;长短布局&#xff…

zblog插件-zblog采集插件下载

在当今数字化的时代&#xff0c;博客已经成为人们分享思想、经验和知识的重要平台。而对于使用zblog博客系统的用户来说&#xff0c;充实博客内容是提高用户体验和吸引读者的不二法门。然而&#xff0c;手动收集内容对于博主来说既费时又繁琐。在这个背景下&#xff0c;zblog插…

线程为什么比进程的切换效率高

1.进程切换为什么比线程切换效率低呢? 进程都有自己的虚拟地址空间&#xff0c;把虚拟地址转换为物理地址需要查找页表&#xff0c;页表查找是一个很慢的过程&#xff0c;因此通常使用Cache来缓存常用的地址映射&#xff0c;这样可以加速页表查找&#xff0c;这个Cache就是TL…

【Cmake】Cmake基础学习

CMake学习 一、基础学习 1. 利用Cmake进行单个源代码构建可执行文件 (1)基础命令 最基本的 CMake项目是由单个源代码文件构建的可执行文件。对于这样的简单项目,只需要一个包含三个命令的 CMakeLists.txt 文件。 注意: 虽然 CMake 支持大写、小写和混合大小写命令,但是…

【Unity3D】MAX聚合广告SDK——Pangle广告接入(成了!成了!)

Pangle, App Monetization Simplified 注册 登录 创建应用 创建广告单元 将其应用ID和广告ID关联到MAX广告。 下载Pangle Unity Plugin包&#xff0c;新建一个空工程&#xff08;很重要&#xff09; Unity版本2019.4.0f1 gradle plugin 4.2.0 gradle版本6.7.1 build_tools 34.…

【Java】7. 类型转换和类型判断

7. 类型转换 7.1 基本类型转换 顺箭头&#xff1a;隐式转换&#xff08;自动&#xff09; 逆箭头&#xff1a;强制转换&#xff08;可能造成精度丢失&#xff09; byte a 10; int b a; int c 1000; byte d (byte) c; System.out.println(d); // -24 7.2 包装类型与基…

GPTS-生成一个动漫图像GPT

介绍 GPTs是ChatGPT的定制版本,用户可以通过组合指令、知识和功能来定制用于特定任务或主题的GPT。它们可以根据需要简单或复杂,解决从语言学习到技术支持等各种事情。 创建GPTs Plus和Enterprise用户可以在chat.openai.com/create上开始创建GPTs。 您可以通过在ChatGPT上的…

印刷企业建设数字工厂管理系统的工作内容有哪些

随着科技的不断进步&#xff0c;数字工厂管理系统在印刷企业中的应用越来越广泛。这种系统可以有效地整合企业内外资源&#xff0c;提高生产效率&#xff0c;降低生产成本&#xff0c;并为印刷企业提供更好的业务运营与管理模式。本文将从以下几个方面探讨印刷企业建设数字工厂…