图论——Djikstra最短路

原理解释

首先解释一下它大概的应用场景以及原理:现在有这么一张图,图上各点之间都有一定的边权或者说是距离。给定你一个起点(例如点1),让你求这个点到图上所有点的最短距离是多少?

这个问题比较平常,但是突然这么一问如果之前没有学过此算法肯定一脸懵。接下来简单解释一下算法的实现思路。

实现思路

  • 定义一个距离数组d\[\]表示起点到此点的最短距离,除了此时的点全部赋为inf

  • 定义一个标记数组v\[\]用来判断此点是否访问过,避免重复访问

  • 对于这个点,每次对它的出点进行遍历,找到距离最小的点处理

  • 如果说此时这条路径到达一个点比之前的路径到达它的距离短,就进行更新

    • 例如点1到点3:
    • 原本是1->3,距离为5
    • 后来路径为1->4->3,距离为4
    • 此时就可以对d3进行更新
  • 最后输出d数组就是起点到所有点的距离了

实现过程演示

代码

cpp 复制代码
vector<pii> e[N];
int d[N],vis[N];
void dji(int s)
{
	for(int i=0; i<=n; i++) d[i]=INF;
	d[s]=0;
	for(int i=1; i<n; i++)//遍历枚举所有点
	{
		int u=0;
		for(int j=1; j<=n;j++)//每次找到此点出点的距离最近点
			if(!vis[j]&&d[j]<d[u]) u=j;
		vis[u]=1;//此点已经当过入点
		for(auto ed:e[u])//对它所有出点进行贪心处理
		{
			int v=ed.v,w=ed.w;
			if(d[v]>d[u]+w)
				d[v]=d[u]+w;
		}
	}
}
void solve()
{
	cin >> n >> m >> s;//点数、边数、起点
	for(int i=0; i<m; i++)
	{
		cin >> a >> b >> c;
		e[a].push_back({b,c});
	}
	dgi(s);
	for(int i=1; i<=n; i++) cout << d[i] << ' ';
}

优化处理

不难看出,这版代码一共用了三个for循环,最多嵌套了两层。时间复杂度极其高,达到了 O ( n 2 + m ) O(n^{2}+m) O(n2+m),所以我们可以对它进行优化处理。

直接跳到时间复杂度最高的地方:找离入点距离最近的出点。如果说此时我们用优先队列的最小堆来维护距离的话,堆顶的元素就一直是离入点最小的了,这样我们就省去了去枚举再遍历着找的步骤。

实现过程演示

代码

cpp 复制代码
priority_queue<pii,vector<pii>,greater<pii>> q;
void dji(int s)//当前点
{
	for(int i=0; i<=n; i++) d[i]=INT_MAX;
	d[s]=0;q.push({0,s});
	while(!q.empty())
	{
		auto t=q.top(); q.pop();
		int u=t.se;
		if(vi[u]) continue;
		vi[u]=1;
		for(auto ed:a[u])
		{
			int v=ed.fi,w=ed.se;
			if(d[u]+w<d[v])//当前路到此点距离比之前更优
			{
				d[v]=d[u]+w;
				q.push({d[v],v});
			}
		}
	}
}
void solve()
{
	cin >> n >> m >> s;//总点数、边的数量、出发点编号
	for(int i=0; i<m; i++)
	{
		int u,v,w;
		cin >> u >> v >> w;
		a[u].push_back({v,w});
	}
	dji(s);
	for(int i=1; i<=n; i++) cout << d[i] << ' ';
}

例题演示

下面看一道类似的例题:B-代价转移

思路

虽然此题看着并没有图,但是Djikstra算法该有的东西此题都能对应上

  • 代价C1,C2,C3看作操作的距离
  • 目前的点就是入点,三种操作之后的数分别代表三个出点
  • 如果a更大的话直接相减就行

代码

cpp 复制代码
void dji()
{
	fill(v,v+N,0);//多实例重置数组
    fill(k,k+N,INF);//赋值
	priority_queue<pii,vector<pii>,greater<pii>> q;
	k[a]=0;//由于要从此点开始,所以设为0
	q.push({0,a});//将起点入队
	maxx=b*2;//所有数中最大可能值,用于边界判断
	while(!q.empty())
	{
		auto [val,num]=q.top();//将当前点之前的值取出来(之前是出点)
		q.pop();
		if(v[num]) continue;//此值当过入点,跳过
		v[num]=1;//此时它是入点,标记
		pii cu[]={{num+1,c1},{num-1,c2},{num*2,c3}};//当前可以到的点
		for(auto [x,y]:cu)
		{
			if(x<1||x>maxx) continue;//边界处理
			if(k[num]+y<k[x])//如果此时的选择比它之前的更优
			{
				k[x]=k[num]+y;//赋值、入队
				q.push({k[x],x});
			}
		}
	}
	cout << k[b] << endl;
}
void solve()
{
	cin >> a >> b >> c1 >> c2 >> c3;
	if(a>=b)//b小的话就只能减了
	{
		cout << (a-b)*c2 << endl;
		return ;
	}
	dji();
}

之前没学的时候总觉得这算法光听名字就很高级,应该还很难。其实它就是一套比较成体系的贪心思想,将图画出来进行演示的话还是比较好理解的。

相关推荐
ZhengEnCi2 小时前
大模型的分类到底怎么分:从基础模型到推理模型、从通用到专用的完整图谱
算法
前进的李工3 小时前
Agent 学习笔记 05:系统提示词应该怎么写
笔记·学习·prompt·agent·个人开发·few-shot·ai应用开发
取名真是3 小时前
Python 算法知识点从基础到进阶
开发语言·python·算法
罗西的思考3 小时前
【轻量化复刻大模型 / KIMI K3】KDA 模块交互式演示
人工智能·算法·机器学习
正在走向自律4 小时前
【3/5】人工智能训练师 三级/高级工 考证学习方向:从“独立执行”到“设计、归因与全链条负责”
人工智能·学习·人工智能训练师·注方案设计·数据质控负责人·模型评测与调优辅助·ai训练项目交付
nm_zfyjt5 小时前
信息流广告投放优化实践:线索成本评估模型与转化链路重构(家装建材案例)
算法·重构·内蒙古朋友圈广告服务商·内蒙古朋友圈获客
CCIE-Yasuo6 小时前
网络安全-学习数据库-Mysql-2
数据库·学习·mysql
La Pulga6 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
w_zero_one6 小时前
算法--构造
java·数据结构·算法
其实防守也摸鱼7 小时前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php