【算法每日一练]-图论(保姆级教程 篇5(LCA,最短路,分层图)) #LCA #最短路计数 #社交网络 #飞行路线 # 第二短路

今天讲最短路统计和分层图

目录

题目:LCA 

思路:

题目:最短路计数

思路:

题目:社交网络

思路:

题目:飞行路线 

思路:

题目:第二短路

思路:


        

        

题目:LCA 

        

思路:

        

非常明显了,之前就说过倍增迭代就是一个一个选区间使总长度达到 M(凑一个数),用不大于它最大的二的次幂,减去之后,再重复这个过程。所以LCA+倍增逼近是最快的。

                

#include<bits/stdc++.h> //最近公共祖先LCA P3379:给一棵数,求任意两点的LCA 
using namespace std;
const int maxn=500002;
int n,m,s,tot=0;
int head[maxn],d[maxn],p[maxn][21];//d存的是深度(deep),p[i][j]存的从i向上走2的j次方那么长的路径到的父节点
struct node{int v,next;}e[maxn*2];//存数要开两倍
void add(int u,int v){e[++tot]={v,head[u]};head[u]=tot;}     
         
void dfs(int u,int fa)// 首先进行的预处理,将所有点的deep和p的初始值dfs出来
{
    d[u]=d[fa]+1; p[u][0]=fa;  //处理深度,父节点
    for(int i=1;(1<<i)<=d[u];i++)//i<log(d[u]) 处理每个u的st表
        p[u][i]=p[p[u][i-1]][i-1];
    for(int i=head[u];i;i=e[i].next){ //处理u的孩子的st表
        int v=e[i].v;
        if(v!=fa) dfs(v,u);//只能向下走,不能向上走
    }
}                              
int lca(int a,int b) //非常标准的lca查找(两次逼近)
{
    if(d[a]>d[b]) swap(a,b);   //保证a是在b结点上方(d[b]大)
    for(int i=20;i>=0;i--){
    	if(d[a]<=d[b]-(1<<i)) b=p[b][i];//向上逼近(b向上移到和a同一个深度)
	}  
    if(a==b) return a;  //特判
    for(int i=20;i>=0;i--)
    {
        if(p[a][i]==p[b][i]) continue; //向上逼近(A和B一起向上,不断逼近最下端的公共祖先)
        else a=p[a][i],b=p[b][i];     
    }
    return p[a][0];  //找出最后a值的数字
}
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);
        add(a,b); add(b,a); //无向图,要加两次              
    }
    dfs(s,0);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        printf("%d\n",lca(a,b));
    }
    return 0;
}

        

         

题目:最短路计数

                  

思路:

        

注意到每条路径的权值都是1,难怪结果会那么大。

        

dikjkstra和spfa版本最短路计数:
1,维护最短路时产生的:那就是映射关系(因为引入的是周围点,相当于ans[v]=ans[cur]*1)
2,新最短路:发现了新的最短路就相加

        
floyd版本最短路计数:
1,维护最短路时产生的:(因为引入的是任意点,故ans[i][j]=ans[i][k]*ans[k][j])
2,新最短路:发现了新的最短路就相加

、        

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int N=1e6+5,M=2e6+5;
int mod=100003,n,m,tot=0;
int head[N],vis[N],dis[N],ans[N];
priority_queue<pii,vector<pii>,greater<pii>>Q;
struct node {int to;int next;}e[M*2];
void add(int u,int v){e[++tot]=(node){v,head[u]};head[u]=tot;}
void dijkstra(int s){
	memset(dis,0x3f,sizeof(dis));
	Q.push({0,s});dis[s]=0;ans[s]=1;
	while(!Q.empty()){
		int cur=Q.top().second;Q.pop();
		if(vis[cur])continue;//跳不跳无所谓,无非耗点时间
		vis[cur]=1;
		for(int i=head[cur];i;i=e[i].next)
		{
			int v=e[i].to;
			if(dis[cur]+1<dis[v])dis[v]=dis[cur]+1,ans[v]=ans[cur],Q.push({dis[v],v});//映射最短路(路过此点可以变短,那么最短路就和它有关)
			else if(dis[cur]+1==dis[v])ans[v]+=ans[cur],ans[v]%=mod;//新最短路(发现了另外的最短路就相加)
		}
	}
}
int main(){
	cin>>n>>m;int x,y;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dijkstra(1);
	//spfa(1);
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<'\n';
	}
}

                 

//spfa版本:这个版本更快!!!!
void spfa(int s){
	memset(dis,0x3f,sizeof(dis));
	queue<int>q;vis[s]=1;
	q.push(s);dis[s]=0;ans[s]=1;
	while(!q.empty()){
		int cur=q.front();q.pop();
		vis[cur]=0;
		for(int i=head[cur];i;i=e[i].next){
			int v=e[i].to;
			if(dis[cur]+1<dis[v]){
			   dis[v]=dis[cur]+1;
			   ans[v]=ans[cur];
			   if(!vis[v])q.push(v),vis[v]=1;	
			}
			else if(dis[cur]+1==dis[v])ans[v]+=ans[cur],ans[v]%=mod;
		}
	}
}

        

        

题目:社交网络

                

思路:

        

点i的重要程度=∑从s到t的且经过i最短路条数/从s到t的最短路条数(s!=i,t!=i)

主要还是floyd算法,求出每个(i,j)对每个k的重要程度为ans[k]
求到某点时最短路径数:
1,只要最短路更新,那么最短路个数也要更新
2,如果发现了新的最短路,那么就相加
        

#include <bits/stdc++.h>
using namespace std;   
typedef long long ll;
const int N=110;
ll INF,dis[N][N],e[N][N];//e[i][j]表示(i,j)的最短路径数
double ans[N];//每个点的重要程度
int main(){
	int n,m;ll x,y,z;
	cin>>n>>m;
	memset(dis,0x7f,sizeof(dis));
	INF=dis[1][1];//初始化INF无穷大
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&x,&y,&z);
		dis[x][y]=dis[y][x]=z;
		e[x][y]=e[y][x]=1;//初始化e[i][j]
	}
	for(int i=1;i<=n;i++)  dis[i][i]=0;//对角线为0,但是不写也对其余任何边都没有影响,写不写随你
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			if(dis[i][k]==INF||dis[k][j]==INF)continue;//有不通的就直接跳过
			if(dis[i][j]>dis[i][k]+dis[k][j]){
				dis[i][j]=dis[i][k]+dis[k][j];//每个边只会更新一次,即当前最优
				e[i][j]=e[i][k]*e[k][j];//只要最短路更新,则最短路对应的个数也要更新即可
				continue;
			}
			if(dis[i][j]==dis[i][k]+dis[k][j]){//找到了第二条最短路,就相加
				e[i][j]+=e[i][k]*e[k][j];
			}
		}
	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)continue;
			if(dis[i][j]==dis[i][k]+dis[k][j])//对k遍历每个(i,j)
				ans[k]+=(1.0*e[i][k]*e[k][j])/e[i][j];
		}
	for(int i=1;i<=n;i++)
		printf("%0.3f\n",ans[i]);
}

       

         

题目:飞行路线 

        

                 

思路:

        

 一个图中任意两个点都可以权值变成0,最多有k次,我们常常建立k层的分层图,相邻层所有点建立权值为0的立体边,然后跑最短路即可
        

#include <bits/stdc++.h> 
using namespace std;
int cnt,head[110005];
int dis[110005];
bool vis[110005]; //标记当前白点,如果不想用vis,也可以判断取出元素的dis和dis数组中值是否一样
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>> > Q; //堆优化(first是值,second是下标)
struct Edge{ int to,w,next;}e[2500001];
void add(int u,int v,int w) { e[++cnt]=(Edge){v,w,head[u]}; head[u]=cnt;}
void Dijkstra(int s)//dijktra+堆优化
{
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    Q.push(make_pair(0,s));
    while(!Q.empty())  //必须用empty, size是求大小的,会慢一些 !!!
    {
		int u=Q.top().second; Q.pop();
		if(vis[u]) continue; //已经是白点的就跳过
	    vis[u]=1; //标记成白点
	    for(int i=head[u];i;i=e[i].next)
	    {
	        int v=e[i].to,w=e[i].w;
	        if(dis[v]>dis[u]+w) dis[v]=dis[u]+w,Q.push(make_pair(dis[v],v));
	    }
    }    
}

int main()
{
	int n,m,k,s,t;
	cin>>n>>m>>k>>s>>t; //城市数,航线数,免费次数,起始城市号,终点城市号
    int u,v,c;
    for(int i=0;i<m;++i)
    {
    	cin>>u>>v>>c;//两个城市航线,费用
    	for(int j=0;j<=k;++j){//建立每层图
    		add(u+j*n,v+j*n,c);
            add(v+j*n,u+j*n,c);
            if(j!=k){//第k层下面没有了,就别建了
            	add(u+j*n,v+(j+1)*n,0); //分层图:所有相邻层间:上下层u,v的权值为0
            	add(v+j*n,u+(j+1)*n,0);
			}
		}
    }
    for(int i=1;i<=k;++i)
	{
		add(t+(i-1)*n,t+i*n,0);
	}//处理奇葩数据
    Dijkstra(s);
    printf("%d",dis[t+k*n]);
    return 0;
}

         

         

题目:第二短路

                 

思路:

#include<bits/stdc++.h>
using namespace std;   
typedef pair<int,int> pii;
const int N=5005,M=100005;
int n,m,tot,flag;
int head[N],d1[N],d2[N],vis[N];
priority_queue<pii,vector<pii>,greater<pii> > Q;
struct node{int to;int w;int next;}e[M*2];
void add(int u,int v,int w){e[++tot]=(node){v,w,head[u]};head[u]=tot;}
void dijkstra(int s){
	memset(d1,0x3f,sizeof(d1));//d1存放第一短路
	memset(d2,0x3f,sizeof(d2));//d2存放第二短路
	Q.push(make_pair(0,s));d1[s]=0;
	while(!Q.empty()){
		int cur=Q.top().second;Q.pop();
		if(vis[cur])continue;//vis数组可有可无,即便旧白点引入也掀不起变化,无非多走了几步
		vis[cur]=1;
		for(int i=head[cur];i;i=e[i].next){
			int v=e[i].to,w=e[i].w;flag=0;
			if(d1[cur]+w<d1[v])d2[v]=d1[v],d1[v]=d1[cur]+w,flag=1;//维护最短路,更新前的最短路就是次短路
			if(d1[cur]+w>d1[v]&&d1[cur]+w<d2[v])d2[v]=d1[cur]+w,flag=1;//最短路没有变化,更新次短路
			if(d2[cur]+w<d2[v])d2[v]=d2[cur]+w,flag=1;//维护次短路,如果d2[s]初始化成0,那么这个地方就出问题了
			if(flag)Q.push(make_pair(d1[v],v));
		}
	}
}
int main(){
	cin>>n>>m;int u,v,w;
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);add(v,u,w);
	}
	dijkstra(1);
	cout<<d2[n];
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谷歌投资Character.AI,展现AI领域的战略布局和创新能力

谷歌&#xff08;Google&#xff09;作为全球最大的互联网公司之一&#xff0c;一直在人工智能&#xff08;AI&#xff09;领域发挥着引领和推动的作用。近日&#xff0c;据消息人士透露&#xff0c;谷歌正与人工智能初创公司 Character.AI 进行投资谈判&#xff0c;计划投资数…

掌握未来技术趋势,Python编程引领人工智能时代

掌握未来技术趋势&#xff0c;Python编程引领人工智能时代 摘要&#xff1a;Python作为一种高级编程语言&#xff0c;在人工智能领域中扮演着越来越重要的角色。本文将通过介绍Python编程的特点、应用场景及发展前景&#xff0c;展望Python未来的发展趋势&#xff0c;并结合代…

【springboot笔记】程序可用性检测ApplicationAvailability

1.背景 springboot-3.1.5 ApplicationAvailability LivenessState ReadinessState AvailabilityChangeEvent 我们可以通过ApplicationAvailability获取当前应用程序的可用性&#xff0c;这个可用性包括ApplicationContext和对外请求路由两种。 LivenessState 是表示Applicatio…

解决docker运行elastic服务端启动不成功

现象&#xff1a; 然后查看docker日志&#xff0c;发现有vm.max_map_count报错 ERROR: [1] bootstrap checks failed [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] 解决办法&#xff1a; 1. 宿主机&#xff08;运行doc…

腾讯云新用户优惠活动有哪些可以参加?腾讯云新人服务器优惠活动

腾讯云作为国内领先的云服务提供商&#xff0c;不仅为用户提供稳定可靠的云服务器&#xff0c;还为新用户带来了一系列的优惠活动和代金券&#xff0c;以降低购买成本&#xff0c;提高业务效益。在这里&#xff0c;我们将为您详细介绍腾讯云服务器的新人优惠活动及代金券&#…

进程程序替换与exec系统调用

进程程序替换 进程程序替换是指将一个正在运行的进程替换为另一个可执行程序。它的本质是调用了Linux操作系统中的exec系统调用。而exec系统调用是一个家族函数&#xff0c;例如execl、execv、execle、execve等。它们的共同特点是当当前进程执行到该函数时&#xff0c;就会直接…

竞赛 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

美颜sdk是什么?美颜sdk技术解析与比较

美颜SDK的出现为开发者提供了快速实现高质量美颜效果的工具&#xff0c;然而&#xff0c;在众多美颜SDK中&#xff0c;技术实现和效果差异巨大。本文将对美颜SDK进行技术解析&#xff0c;并进行比较&#xff0c;以帮助开发者更好地选择适合其应用需求的美颜SDK。 一、美颜SDK…

GCD:异步同步?串行并发?一文轻松拿捏!

GCD 文章目录 GCD进程线程进程与线程的关系进程与线程的区别 任务&#xff08;执行的代码&#xff09;队列线程与队列的关系 队列任务**同步执行任务&#xff08;sync&#xff09;**辅助方法**异步执行任务&#xff08;async)**总结栅栏任务迭代任务 队列详细属性QoSAttributes…

视频剪辑技巧:简单步骤,批量剪辑并随机分割视频

随着社交媒体平台的广泛普及和视频制作需求的急剧增加&#xff0c;视频剪辑已经成为了当今社会一项不可或缺的技能。然而&#xff0c;对于许多初学者来说&#xff0c;视频剪辑可能是一项令人望而生畏的复杂任务。可能会面临各种困难&#xff0c;如如何选择合适的软件和硬件、如…

Vue3 shallowRef 和 shallowReactive

一、shallowRef 使用shallowRef之前需要进行引入&#xff1a; import { shallowRef } from vue; 使用方法和ref 的使用方法一致&#xff0c;以下是二者的区别&#xff1a; 1. 如果ref 和 shallowRef 都传入的是普通数据类型的数据&#xff0c;那么他们的效果是一样的&#x…

​软考-高级-系统架构设计师教程(清华第2版)【第18章 安全架构设计理论与实践(P648~690)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第18章 安全架构设计理论与实践&#xff08;P648~690&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

【C++】chono库:使用及源码分析

文章目录 0. 概述1. duration1.1 分析std::chrono::duration_cast() 1.2 使用案例std::chrono::duration::count() 1.3 部分源码 2. time_point2.1 分析std::chrono::time_point_cast() 2.2 使用举例std::chrono::time_point::time_since_epoch() 2.3 部分源码 0. 概述 本篇文…

将ArduinoIDE库文件移动到其他磁盘的方法

本文主要介绍更改软件包位置Arduino IDE &#xff08;含2.0以上版本&#xff09;的方法。 Arduino IDE 默认将软件包安装到 C 盘&#xff0c;如果你使用的开发板较多&#xff0c;产生的库文件很大&#xff0c;会导致 C 盘可用空间不足&#xff0c;博主只用了ESP开发板&#xf…

Python程序打包指南:手把手教你一步步完成

最近感兴趣想将开发的项目转成Package&#xff0c;研究了一下相关文章&#xff0c;并且自己跑通了&#xff0c;走了一下弯路&#xff0c;这里记录一下如何打包一个简单的Python项目&#xff0c;展示如何添加必要的文件和结构来创建包&#xff0c;如何构建包&#xff0c;以及如何…

纯CSS自定义滚动条样式

.my-carousel{height: 474px;overflow-y: auto; } /*正常情况下滑块的样式*/ .my-carousel::-webkit-scrollbar {width: 5px; } .my-carousel::-webkit-scrollbar-thumb {border-radius: 8px;background-color: #ccc; } .my-carousel::-webkit-scrollbar-track {border-radius:…

生活总是自己的,请尽情打扮,尽情可爱,,

同色系拼接羽绒服了解一下 穿上时尚感一下子就突显出来了 90白鸭绒填充&#xff0c;不仅时尚还保暖 设计感满满的羽绒服不考虑一下吗?

Git企业开发级讲解(四)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、理解分⽀二、创建分支三、切换分⽀四、合并分⽀五、删除分⽀六、合并冲突七、分⽀管理策略…

Windows10下Maven3.9.5安装教程

文章目录 1.下载maven2.安装3.配置系统变量3.1.新建系统变量 MAVEN_HOME3.2.编辑系统变量Path 4.CMD命令测试是否安装成功5.配置maven本地仓库6.配置国内镜像仓库 1.下载maven 官网 https://maven.apache.org/download.cgi 点击下载。 2.安装 解压到指定目录 D:\installSoft…

vue3基础学习

##以前怎么玩的? ###MVC Model:Bean View:视图 Controller ##vue的ref reactive ref:必须是简单类型 reactive:必须不能是简单类型 ###创建一个Vue项目 npm init vuelatest ###生命周期 ###setup相关 ####Vue2的一些写法 -- options API ####Vue3的写法 组合式API Vu…