首页 > 编程语言 >关于 最短路 及其 拓展算法 的粗浅总结

关于 最短路 及其 拓展算法 的粗浅总结

时间:2024-09-22 18:46:35浏览次数:1  
标签:粗浅 tote int 短路 vis 算法 节点 dis

关于 最短路 及其 拓展算法 的粗浅总结

最短路(Dijkstra)

Core_Code

inline void dijkstra()
{
    memset(vis,0,sizeof vis);
 	memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    priority_queue<pair<int,int> >q;
    q.push(make_pair(dis[s],s));
    while(!q.empty())
    {
		int x=q.top().second;q.pop();
        if(vis[x])continue;
        for(int i=head[x];i;i=E[i].nex)
        {
			int v=E[i].v;
             if(dis[x]+E[i].w<dis[v])
             {
                 dis[v]=dis[x]=E[i].w;
                 q.push(make_pair(-dis[v],v));
			}
        }
        vis[x]=1;
    }
}

正确性

不过多阐述了,只用简单的话讲讲我个人对这个算法的理解。

假设我们已经找到了所有的最短路,那么考虑对于一个节点 \(x\) ,其最短路 \(dis[x]\) 一定是从相邻的 \(v\) 的最短路 \(dis[v]\) 转移而来的,不难用反证法证得。言下之意,如果我们确定了当前的点的最短路 \(dis[now]\) ,那么我们就可以用 \(now\) 去更新周围的点,得到所有周围点 \(v\) 的 疑似 最短路,也就是我们所说的 松弛 操作 。之所以说是 疑似 ,是因为在这之后可能还会有其他的节点来对当前点 \(now\) 进行更新。

不难注意到,在对堆内元素进行枚举的时候,我们取出的 \(dis\) 序列是单调递增的,假设我们要求出 \(x\) 点的最短路,而 \(dis[x]\) 已经在优先队列中,那么所有可能对 \(dis[x]\) 进行更新的节点在优先队列中都位于它之前,当我们枚举到了 \(dis[x]\) 时,说明已经检查过了前面的节点是否会对它产生影响,那么这是他就一定是全局中的最短路,于是我们再用它对于之后的节点进行 松弛 ,之后再标记 \(vis[x]=1\) ,代表已经计算出它的最短路。用时间顺序表示如下:

​ 检查之前的节点 \(\rightarrow\) 枚举到 \(x\) ,成功得到 \(dis[x]\) \(\rightarrow\) 用 \(x\) 去更新可能的 疑似 最短路。

扩展

分层最短路

常常用于有不同寻常的前行方式的变种最短路问题,用分层的方式来记录不同的状态

过程类似于网络流的建模。

P4568 [JLOI2011] 飞行路线

最短路中有 \(K\) 次白嫖边权的机会,问此时的最短路是多少。

我们建 \(K\) 层图,初始位于最下面的一层,在常规建边的基础上,我们给每一条边一个向上一层的机会,也就是其中一个节点变为更高一层的节点,边权为 \(0\) 。这样就保证了一共可以上 \(K\) 层,也就是白嫖 \(K\) 次。

CF2014E

仍然是普通的最短路,但是到了某些节点之后(有马),就可以使得之后的前进过程都只消耗 \(w/2\) 的代价,并且是两个人同时出发,最后在一点汇合(可以停下等待)。

后者非常好解决,我们只需要跑两次最短路,然后枚举中间汇合的点就好了。

那么如何处理前者?就要用到分层最短路。

对于任何一个有马的节点,我们都向更高一层建一条边,而更高一层的所有边权都是底层对应的一半。最后的最短路就是两张图取一个 min 就行。

#include<bits/stdc++.h>
#define int long long 
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int n,m,h;
struct Edge
{
	int u,v,w,nex;
}e[2000010];
int tote,head[400010],vis[400010];
inline void add(int u,int v,int w)
{
	e[++tote].u=u,e[tote].v=v,e[tote].w=w;
	e[tote].nex=head[u],head[u]=tote;
}
struct Node
{
	int x,dis;
};
bool operator <(Node a,Node b)
{
	return a.dis>b.dis;
}
const int inf=1e15+1;
int dis1[400010],disn[400010];
inline void dj()
{
	for(register int i=1;i<=2*n;++i)dis1[i]=inf,vis[i]=0;
	dis1[1]=0;
	priority_queue<Node> q;
	q.push(Node{1,0});
	while(q.size())
	{
		int x=q.top().x;q.pop();
		if(vis[x])continue;
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].v,w=e[i].w;
			if(dis1[x]+w<dis1[v])
			{
				dis1[v]=dis1[x]+w;
				q.push(Node{v,dis1[v]});
			}
		}
		vis[x]=1;
	}
	
	for(register int i=1;i<=2*n;++i)disn[i]=inf,vis[i]=0;
	disn[n]=0;
	priority_queue<Node> q1;
	q1.push(Node{n,0});
	while(q1.size())
	{
		int x=q1.top().x;q1.pop();
		if(vis[x])continue;
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].v,w=e[i].w;
			if(disn[x]+w<disn[v])
			{
				disn[v]=disn[x]+w;
				q1.push(Node{v,disn[v]});
			}
		}
		vis[x]=1;
	}
	
}	
inline void pre()
{
	tote=0;
	memset(head,0,sizeof(head));
	re(n),re(m),re(h);
	int tmp;
	for(register int i=1;i<=h;++i)
	{
		re(tmp);
		add(tmp,tmp+n,0);
	}
	for(register int i=1;i<=m;++i)
	{
		int u,v,w;
		re(u),re(v),re(w);
		add(u,v,w),add(v,u,w);
		add(u+n,v+n,w/2),add(v+n,u+n,w/2);
	}
	dj();
//	puts("display:");
//	for(register int i=1;i<=n;++i)printf("%lld ",dis1[i]);
//	printf("\n");
//	for(register int i=1;i<=n;++i)printf("%lld ",disn[i]);
//	printf("\n");
}
inline void solve()
{
	int ans=1e15+2;
	for(register int i=1;i<=n;++i)
	{
		if(dis1[i]==inf||disn[i]==inf)continue;
		ans=min(ans,max(min(dis1[i],dis1[i+n]),min(disn[i],disn[i+n])));
	}
	if(ans==1e15+2)puts("-1");
	else wr(ans),putchar('\n');
}
signed main()
{
	int T;
	cin>>T;
	while(T--)
	{
		pre();
		solve();
	}
	return 0;
}

标签:粗浅,tote,int,短路,vis,算法,节点,dis
From: https://www.cnblogs.com/Hanggoash/p/18425665

相关文章

  • 强化学习基础:主要算法框架与Python实现示例
    创作不易,您的打赏、关注、点赞、收藏和转发是我坚持下去的动力!强化学习(ReinforcementLearning,RL)是一种通过与环境交互来学习策略的机器学习方法。RL主要包含以下几个关键组件:状态(State)、动作(Action)、奖励(Reward)、策略(Policy)和价值函数(ValueFunction)。常见的强化学习主流......
  • 药物分子生成算法综述:从生成对抗网络到变换器模型的多样化选择
    创作不易,您的打赏、关注、点赞、收藏和转发是我坚持下去的动力!基于已有的药物数据生成新的药物分子是一项复杂的任务,通常涉及到生成模型和机器学习算法。以下是一些常用的算法和方法:1.生成对抗网络(GANs)特点:由生成器和判别器两个神经网络组成,生成器生成新分子,判别......
  • Tarjan算法及其应用 总结+详细讲解+详细代码注释
    \(\text{Tarjan}\)1.引入概念1.强连通分量1.定义在有向图\(G\)中,强连通分量就是满足以下条件的\(G\)的子图:从任意一点出发,都有到达另一个点的路径。不存在一个或者几个点,使得这个子图加入这些点后,这个子图还满足上一个性质。为什么要限定”在有向图中“而不是”在任......
  • 文心一言 VS 讯飞星火 VS chatgpt (352)-- 算法导论24.1 3题
    三、给定G=(V,E)是一带权重且没有权重为负值的环路的有向图,对于所有结点v∈V,从源结点s到结点v之间的最短路径中,包含边的条数的最大值为m。(这里,判断最短路径的根据是权重,不是边的条数。)请对算法BELLMAN-FORD进行简单修改,可以让其在m+1遍松弛操作之后终止,即使m不是......
  • 【蓝桥杯】2024.9.22算法赛——灵魂问题\全栈项目小组(C++)
    一、灵魂问题题目灵魂问题题目分析1.要求输出一个整数2.题目在玩脑筋急转弯,关键句子标出来了——糖什么的根本不重要。所以咖啡不加糖,答案是0!!!代码#include<iostream>usingnamespacestd;intmain(){ cout<<0; return0;}二、全栈项目小组题目全栈项目小组......
  • 几种常用的算法(递归,Top-n)
    //C#用递归算法实现:一列数的规则如下:1、1、2、3、5、8、13、21、34,求第30位数是多少 publicstaticintGetPosValue(intpos) {    //第1位、第2位,实际上索引是0、1    if(pos==0||pos==1) //我们习惯上,位置使用索引(从0开始,0视为是第1位)    {   ......
  • [数据结构与算法·C++] 笔记 1.4 算法复杂性分析
    1.4算法复杂性分析算法的渐进分析数据规模n逐步增大时,f(n)的增长趋势当n增大到一定值以后,计算公式中影响最大的就是n的幂次最高的项其他的常数项和低幂次项都可以忽略大O表示法函数f,g定义域为自然数,值域非负实数集定义:如果存在正数c和n,使得对任意的......
  • 【代码随想录Day24】回溯算法Part03
    93.复原IP地址题目链接/文章讲解:代码随想录视频讲解:回溯算法如何分割字符串并判断是合法IP?|LeetCode:93.复原IP地址_哔哩哔哩_bilibiliclassSolution{List<String>result=newArrayList<>();LinkedList<String>path=newLinkedList<>();publicL......
  • 算法解析:二分查找实现整数平方根
    题目:给你一个非负整数 x ,计算并返回 x 的算术平方根 。由于返回类型是整数,结果只保留整数部分 ,小数部分将被舍去。注意:不允许使用任何内置指数函数和算符,例如 pow(x,0.5) 或者 x**0.5 。示例1:输入:x=4输出:2示例2:输入:x=8输出:2解释:8的算术平方根是2.82842.........
  • 初识算法
    持续更新数据结构与算法专题,欢迎关注.......1.1什么是算法?定义在数学和计算机科学领域,算法是一系列有限的严谨指令,通常用于解决一类特定问题或执行计算Inmathematicsandcomputerscience,analgorithm(/ˈælɡərɪðəm/)isafinitesequenceofrigorousinstru......