【算法每日一练]-图论(lca) 最近公共祖先LCA,货车运输

目录

P3379:最近公共祖先LCA

思路:

货车运输


        

       

P3379:最近公共祖先LCA

思路:

首先进行的预处理,将所有点的深度和p数组求出来

设置:p[i][j]存的从i向上走2的j次方那么长的路径到的父节点

更深的点走到和另一个点相同的深度(倍增快速逼近),然后两个点同时走到最下端的公共祖先(倍增快速逼近)

#include<bits/stdc++.h> 
using namespace std;
const int N=500005;
int n,m,s;
vector<int>ve[N];
int d[N],p[N][21];//d存的是深度(deep),p[i][j]存的从i向上走2的j次方那么长的路径到的父节点     
void dfs(int u,int fa){//首先预处理,将所有点的deep值dfs出来,完成p表的创建for(auto v: ve[u]){if(v==fa)continue;d[v]=d[u]+1;p[v][0]=u;dfs(v,u);}
}                              
int lca(int a,int b){ //非常标准的lca查找(两次逼近)if(d[a]>d[b]) swap(a,b);   //保证a是在b结点上方for(int i=20;i>=0;i--)if(d[a]<=d[p[b][i]]) b=p[b][i]; //达到同一深度if(a==b) return a;  //特判for(int i=20;i>=0;i--)if(p[a][i]!=p[b][i]) a=p[a][i],b=p[b][i];  //向上逼近A和B一起向上return p[a][0];  //最后再向上走一步
}int main(){int a,b;scanf("%d%d%d",&n,&m,&s);//n个结点,m次询问,s是树根编号for(int i=1;i<n;i++){scanf("%d%d",&a,&b);ve[a].push_back(b);ve[b].push_back(a);              }d[s]=1;dfs(s,0);//初始化每个点的deep和p[v][0]for(int j=1;j<=20;j++)for(int i=1;i<=n;i++)p[i][j]=p[p[i][j-1]][j-1];for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);printf("%d\n",lca(a,b));}return 0;
}

        

        

货车运输

一模一样,就拿这道做过的题来说把:

题意是要路径上最小的权值链路最大,如果是单源问题还是可以dijkstra的。

但是这个题是多源问题,就要kruskal+lca。

首先解释一下为什么要用kruskal:

那么不妨假设求u到v的路径,我们要所有由u通往v的路径中最小边权中最大的路径,那么如果我们按照最大生成树去建图,是不是图中任意两点间建立的路径都是最大路径?因为那些更小的边我们都没用上。可以设想一下如果u到v还有别的额外的路径,那么这些路径之所有没有没用上,不就是因为有的边权太小了。

然后是lca:

我们在建完树后,为什么就会想到lca呢?

首先这个时候我们要求两个点的路径,其实已经变得唯一了,而且必须找到最近公共祖先,所以需要用到lca

其次我们要求u到v的最小边权,那么这个最小边权如果一个一个的跑不就又变成n^n了吗,怎么办?这时候可以想到离线求极值的方法:倍增,线段树。

说到树上倍增,你最快的是不是想到lca

所以我们可以设置w[i][j]表示从i开始向上走2^j到长度对应的小的权值。然后从i开始走2^j长度路径上的最小权值。

同样设置:f[i][j]表示从i开始向上走2^j到的节点

这样就可以在逼近的时候一遍使用w来更新答案,一边使用f找公共祖先

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=3e5+5,inf=1e9;
int tot,n,m,q,head[N],deep[N],f[N][21],w[N][21],fa[N];
//f[i][j]表示从i开始向上走2^j到的节点,w[i][j]表示从i开始向上走2^j到长度对应的小的权值
bool vis[N];
struct edge1{int u,v,w;}e1[M];
struct edge2{int v,w,next;}e2[N];
int find(int x){if(x!=fa[x])fa[x]=find(fa[x]);return fa[x];
}
void add(int u,int v,int w){e2[++tot]=(edge2){v,w,head[u]};head[u]=tot;}
bool cmp(edge1 a,edge1 b){return a.w>b.w;}
void kruskal(){for(int i=1;i<=n;i++) fa[i]=i;//初始化并查集sort(e1+1,e1+1+m,cmp);//建立最大生成树for(int i=1;i<=m;i++){ int u=e1[i].u,v=e1[i].v,w=e1[i].w;int f1=find(u),f2=find(v);if(f1!=f2){ //建立重构树fa[f1]=f2;//合并并查集add(u,v,w);add(v,u,w);}}
}
void dfs(int u,int faa){//初始化每个点的deep[v],f[v][0],w[v][0]vis[u]=1;for(int i=head[u];i;i=e2[i].next){int v=e2[i].v;if(v==faa)continue;deep[v]=deep[u]+1;f[v][0]=u;w[v][0]=e2[i].w;dfs(v,u);//先更新自己再更新孩子}
}
int lca(int x,int y){if(find(x)!=find(y))return -1;int ans=inf;if(deep[x]>deep[y])swap(x,y);//让左边y向右边x靠近for(int i=20;i>=0;i--){//达到相同深度if(deep[f[y][i]]>=deep[x]){ans=min(ans,w[y][i]); y=f[y][i];//每上升一次就要更新此距离上的最小值。修改y位置}}if(x==y)return ans;//第一次返回for(int i=20;i>=0;i--){//一起上升到没有公共祖先为止if(f[x][i]!=f[y][i]){ans=min(ans,min(w[x][i],w[y][i]));//每上升一次就要更新两段距离上的最小值。x=f[x][i];y=f[y][i];}}ans=min(ans,min(w[x][0],w[y][0]));//此时再往上一格就是lca,所以再更新一次return ans;
}
int main(){cin>>n>>m>>q;for(int i=1;i<=m;i++){cin>>e1[i].u>>e1[i].v>>e1[i].w;}kruskal();for(int i=1;i<=n;i++){if(vis[i])continue;deep[i]=1;dfs(i,0);f[i][0]=i;w[i][0]=inf;//初始化根的信息}for(int i=1;i<=20;i++){//初始化倍增表for(int j=1;j<=n;j++){f[j][i]=f[f[j][i-1]][i-1];//距离倍增表w[j][i]=min(w[j][i-1],w[f[j][i-1]][i-1]);//极值倍增表}}int x,y;for(int i=1;i<=q;i++){cin>>x>>y;cout<<lca(x,y)<<'\n';}return 0;}

当然如果你只是骗分,那么直接floyd就可以。

设置dp[i][j]表示i到j路径上的存在的最小边权,

根据: dp[i][j]=max(dp[i][j],min(dp[i][k],dp[k][j]))进行转移

当然前提是i能到k,k能到j 。然后至少能拿小半分了。

 memset(dp,-1,sizeof(dp));cin>>n>>m>>q;while(m--){int u,v,x;cin>>u>>v>>x;dp[u][v]=max(dp[u][v],x);   //如果有重边,选稳定性最大的一条路dp[v][u]=max(dp[v][u],x);}for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i!=j&&j!=k&&i!=k){   //用K中转的路径 更新dp[i][j]dp[i][j]=max(dp[i][j],min(dp[i][k],dp[k][j]));}}}}while(q--){int x,y;cin>>x>>y;cout<<dp[x][y]<<endl;}

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

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

相关文章

PostgreSQL入门到实战-第二十二弹

PostgreSQL入门到实战 PostgreSQL中表连接操作(六)官网地址PostgreSQL概述PostgreSQL中self-join命令理论PostgreSQL中self-join命令实战更新计划 PostgreSQL中表连接操作(六) 使用PostgreSQL自联接技术来比较同一表中的行 官网地址 声明: 由于操作系统, 版本更新等原因, 文…

内存函数memcpy、mommove、memset、memcmp

1、memcpy函数 描述&#xff1a; C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。 声明&#xff1a; void *memcpy(void *str1, const void *str2, size_t n)参数&#xff1a; str1 -- 指向用于存储复制内容的目标…

【电控笔记0】稳定度判断

简要概括 现控:原理虚轴,稳定度越高 自控:相位裕度PM 增益裕度GM 开环传函 不稳定条件判断

期望阻抗(Zd/s或Yd*s)的nyquist、bode与rlocus

在机器人控制领域中&#xff0c;针对具体的阻抗参数特性&#xff08;如质量、阻尼和刚度&#xff09;&#xff0c;Nyquist图、Bode图和根轨迹&#xff08;rlocus&#xff09;可以提供深入的分析和设计工具。 Nyquist图&#xff1a; 应用于阻抗参数&#xff1a;在机器人控制中&…

docker pull镜像的时候指定arm平台

指定arm平台 x86平台下载arm平台的镜像包 以mysql镜像为例 docker pull --platform linux/arm64 mysqldocker images查看镜像信息 要查看Docker镜像的信息&#xff0c;可以使用docker inspect命令。这个命令会返回镜像的详细信息&#xff0c;包括其元数据和配置。 docker i…

Fast-lio2运行时如何显示轨迹线

修改对应设备的.yaml文件&#xff0c;以velodyne为例&#xff1a; 将 path_en参数改为true即可&#xff0c;运行其他设备&#xff0c;修改对应的参数

四、SpringBoot3 整合 Druid 数据源

本章概要 创建程序引入依赖启动类配置文件编写编写 Controller启动测试问题解决 4.1 创建程序 4.2 引入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://ww…

【C++ STL序列容器】deque 双端队列

文章目录 【 1. 基本原理 】【 1. deque 的创建 】1.1 创建一个空的 deque1.2 创建一个 n 个默认值的 deque1.3 创建一个 n 个指定值的 deque1.4 通过一个 deque 初始化另一个 deque1.5 通过基础容器来初始化 queue 容器适配器 【 3. deque 支持的成员函数 】 【 1. 基本原理 】…

不惑之年,反思我如何成为一个程序员

不惑之年&#xff0c;反思我如何成为一个程序员 文章目录 不惑之年&#xff0c;反思我如何成为一个程序员01/偶然掉入码河02/现实撕碎理想03/发展选择方向04/时代成就向往05/幸运装饰未来 在这个充满生机与希望的季节&#xff0c;博主有幸收到一家国企邀约面试&#xff0c;并顺…

通俗易懂HTTP和HTTPS区别

HTTP&#xff1a;超文本传输协议&#xff0c;它是使用一种明文的方式发送我们的内容&#xff0c;没有任何的加密&#xff0c;例如我们要在网页上输入账号密码&#xff0c;如果使用HTTP协议&#xff0c;账号密码就可能会被暴露&#xff0c;默认端口是80. HTTPS&#xff1a;是HT…

护眼台灯品牌哪个好?2024五大护眼台灯排行榜分享

​护眼台灯作为家庭中常见的照明工具&#xff0c;其存在几乎成为了现代生活的标配。家长们往往会为孩子购置一台&#xff0c;供学习和阅读使用&#xff1b;同时&#xff0c;它也是学生和办公人员在夜晚工作学习的必备之物。然而&#xff0c;市面上的一些普通台灯可能存在着种种…

Springboot使用教程

二、配置文件 SpringBoot使用一个全局的配置文件&#xff0c;配置文件名是固定的&#xff1b; •application.properties •application.yml 1.配置文件的作用&#xff1a; 修改SpringBoot自动配置的默认值&#xff1b;SpringBoot在底层都给我们自动配置好&#xff1b; Y…

OpenHarmony的C/C++三方库的适配

简介 本仓库主要用于存放已经适配OpenHarmony的C/C三方库的适配脚本和OpenHarmony三方库适配指导文档、三方库适配相关的工具。 三方库适配 本仓库的三方库主要是通过OpenHarmony SDK进行交叉编译适配的&#xff0c;并集成到应用端进行使用。 在使用OpenHarmony的SDK进行交…

智能合约:未来数字经济的基石

智能合约是一种自动执行交易的计算机协议&#xff0c;它以代码形式规定了交易双方的权利和义务&#xff0c;具有高度的可靠性和安全性。随着数字经济的发展&#xff0c;智能合约的重要性日益凸显&#xff0c;将成为未来数字经济的基石。 首先&#xff0c;智能合约在金融领域的应…

【目标检测数据集】城市街道垃圾堆相关数据集

一、GarbageOverflow&#xff1a;城市街道垃圾堆数据集 该垃圾堆数据集是通过爬虫从网上进行爬取得到的&#xff0c;一共包含1188张图片&#xff0c;有2个类别&#xff0c;分别为[overflow, No Overflow]&#xff0c;两个标签的数量分别为1734个标签和414个标签。部分数据集及…

23年坚守,只为打造高品质立秀膨体,索康让品质为中国说话

2024年3月23日&#xff0c;第二十三届上海国际整形美容外科大会&#xff08;以下简称“大会”&#xff09;在上海召开&#xff0c;本次大会由张涤生整形外科发展基金会主办&#xff0c;上海交通大学附属第九人民医院整复外科、Chinese Journal of Plastic and Reconstructive S…

阿里云2核2G服务器这么便宜,能用来做什么?

阿里云2核2G服务器这么便宜&#xff0c;能用来做什么&#xff1f;阿里云2核2G云服务器可以用来搭建网站、爬虫、邮件服务器、接口服务器、个人博客、企业官网、数据库应用、大数据计算、AI人工智能、论坛、电子商务、AI、LLM大语言模型、测试环境等&#xff0c;阿里云2核2G服务…

Uniapp+基于百度智能云完成AI视觉功能(附前端思路)

本博客使用uniapp百度智能云图像大模型中的AI视觉API&#xff08;本文以物体检测为例&#xff09;完成了一个简单的图像识别页面&#xff0c;调用百度智能云API可以实现快速训练模型并且部署的效果。 uniapp百度智能云AI视觉页面实现 先上效果图实现过程百度智能云Easy DL训练图…

Hi3861 OpenHarmony嵌入式应用入门--鸿蒙开发环境搭建

目录 简介 准备材料 安装开发环境 配置开发工具和sdk 新建工程 代码编译 简介 本篇将进行hi3861开发环境的搭建&#xff0c;并能够编译默认工程。 准备材料 华为集成开发环境工具DevEco Device Tool 华为集成开发环境IDE DevEco Device Tool下载 | HarmonyOS设备开发 …

SpringBoot自动配置原理(超级干货,直接面试使用,没有长篇大论)

SpringBoot的自动配置 遵循约定大于配置的原则&#xff0c;在boot程序启动后&#xff0c;起步依赖中的一下bean对象会自动注入到ioc容器 当面试官问你&#xff1a;说一说SpringBoot自动配置原理 你回答&#xff1a; 如此回答不到一分钟就过了&#xff0c;主打简单真实好用&am…