首页 > 编程语言 >最短路算法(Dijkstra + SPFA + Floyd)

最短路算法(Dijkstra + SPFA + Floyd)

时间:2024-04-12 22:55:05浏览次数:22  
标签:dist int graph SPFA Dijkstra Floyd INF dis

最短路算法(Dijkstra + SPFA + Floyd)

Dijkstra算法

1.算法基本介绍

Dijkstra算法通常是求解单源最短路中最快的算法,但它无法处理存在负权边的情况(原因在正确性证明中)。Dijkstra本质上是一种贪心算法,通过不断调整每个点的“当前距离”最终得到最优结果,其实后面要讲到的几种算法也大都是采用这种步步逼近的手段。这种不断调整的过程,维基百科上面称为“relax"。以上可能有点抽象,下面是算法的流程。

原题链接:Dijkstra Algorithm - Problems - Eolymp

例题1:

The directed weighted graph is given. Find the shortest path from the vertex s to the vertex f.

Input data

The first line contains three numbers n, s and f (1n100, 1s, fn), where n is the number of vertices in a graph. Each of the next n lines contains n numbers - the adjacency matrix of the graph, where the number in the i-th line and j-th column corresponds to the edge from i to j: -1 means the absence of the edge between the vertices, and any non-negative number - the presence of the edge of a given weight. The main diagonal of the matrix contains always zeroes.

Output data

Print the required distance or -1 if the path between the given vertices does not exist.

Examples

Input example #1

3 1 2
0 -1 2
3 0 -1
-1 4 0

Output example #1

6

Vector版本:

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int main() 
{
    int n, s, f;
    cin >> n >> s >> f;
    vector<vector<int>> graph(n, vector<int>(n));//定义了一个n行n列的graph向量
    for (int i = 0; i < n; i++) 
	{
        for (int j = 0; j < n; j++) 
		{
            cin >> graph[i][j];//输入邻接矩阵的权
        }
    }

/*
dist 向量表示起点 s 到每个节点的最短距离,初始化为无穷大。
visited 向量用于标记每个节点是否被访问过,初始化为 false。
*/
    vector<int> dist(n, INF);//初始化dis
    vector<bool> visited(n, false);//初始化visited
    dist[s-1] = 0;        //s到自身的距离为0

    for (int i = 0; i < n; i++) 
	{
        int u = -1;//给出一个非法值,判断判断是否已经找到了离起点最近的未访问节点。
        //如果 u 的值不是 -1,说明找到了离起点最近的未访问节点.
		for (int j = 0; j < n; j++) 
		{
            if (!visited[j] && (u == -1 || dist[j] < dist[u])) //判断当前节点 j 是否为起点 s 的第一个访问节点
			{
                u = j;
            }
        }

        if (dist[u] == INF) 
		{
            break;//如果 u 的值仍然为 -1,说明没有找到符合条件的未访问节点,此时就需要结束 Dijkstra 算法的迭代
        }

        visited[u] = true;
        for (int v = 0; v < n; v++) 
		{
            if (graph[u][v] != -1)//-1的时候是两点间并未相连 即没有路径可走
			{
                int alt = dist[u] + graph[u][v];
                if (alt < dist[v]) 
				{
                    dist[v] = alt;
                }
            }
        }
    }

    if (dist[f-1] == INF) 
	{
        cout << -1 << endl;
    } 
	else 
	{
        cout << dist[f-1] << endl;
    }
	/*
	最后,检查 dist[f-1] 的值,如果为无穷大,则说明起点 s
	无法到达终点 f,输出 -1。否则,输出起点 s
	*/
    return 0;
}
/*
输入:
3 1 2
0 -1 2
3 0 -1
-1 4 0

输出:
6
*/

例题二:

Background
\(\mathrm{A}\) 地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。

Description
给出 \(\mathrm{A}\) 地区的村庄数 \(N\) ,和公路数 \(M\) ,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路 (可以由多条公路连成一条道路)。

Input
第 1 行两个正整数 \(N, M\) 。
下面 \(M\) 行,每行 3 个正整数 \(x, y, t\) ,告诉你这条公路连着 \(x, y\) 两个村庄,在时间诗能修复完成这条公路。

Output
如果全部公路修复完毕仍然存在两个村庄无法通车,则输出 -1 ,否则输出最早什么时候任意两个村庄能够通车。

样例输入:

4 4
1 2 6
1 3 4
1 4 5
4 2 3

样例输出

5

朴素版本:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
const int INF=0x3f3f3f3f;
int graph[N][N];//邻接矩阵
int dis[N];//起点到目标点的距离
int v[N];//判断这个点是否走过
int n,m;
int u,p,w;
void dijkstra()
{
    memset(dis,INF,sizeof(dis)); //将起点到各个点的距离初始化为INF
    dis[1]=0; //起点到自己的距离为0
    for(int i=1;i<=n;i++) //共进行n轮
    {
        int t=-1; //t为距离起点最近的未访问的点
        for(int j=1;j<=n;j++)
        {
            if(v[j]==0&&(t==-1||dis[t]>dis[j])) //如果j未被访问过且到j的距离更近
            {
                t=j; //更新t为j
            }
        }
        v[t]=1; //标记t为已访问过
        for(int j=1;j<=n;j++)
        {
            dis[j]=min(dis[j],dis[t]+graph[t][j]); //用t更新起点到j的距离
        }
    }
    cout<<dis[n]<<endl; //输出起点到终点的最短距离
}
int main()
{
    cin>>m>>n; //输入边的数量m和点的数量n
    memset(graph,INF,sizeof(graph)); //将邻接矩阵初始化为INF
    for(int i=1;i<=m;i++) //输入m条边
    {
        cin>>u>>p>>w;
        graph[u][p]=graph[p][u]=min(graph[u][p],w); //将u和p之间的边权设置为w
    }
    dijkstra(); //运行Dijkstra算法
    return 0;
}

例题三:

原题链接:[2387 -- Til the Cows Come Home (poj.org)]

史学长很热爱学习,他打算假期偷偷跑回学校学习,为了多学习他希望可以找最快的路线回到学校。 洛阳市里有N个(2 <= N <= 1000)个地铁站,编号分别为1..N。他的家在1号地铁站旁边,洛阳师范学院站是N号地铁站。地铁站之间共有M (1 <= M <= 2000)条双向路径。 史学长现在在1号地铁站,他希望知道到学校最短要多长时间。可以保证史学长能到达学校。忽略史学长在换乘地铁时需要的等待时间。

Input

* 第一行输入两个整数m和n

* 接下来m行,每行三个整数a、b、c,表示a号地铁站和b号地铁站间要花费时间c(1<=c<=100).

Sample

Input

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100

Output

90

代码:

/*
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
*/
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2010;
const int INF=0x3f3f3f3f;
int v[N],graph[N][N];
int dis[N];
int n,m,a,b,c;
void dijkstra()
{
	memset(dis,INF,sizeof(dis));
	dis[1]=0;
	for(int i=1;i<=n;i++)
	{	
		int t=-1;
		for(int j=1;j<=n;j++)
		{
			if(v[j]==0&&(t==-1||dis[t]>dis[j]))
			{
				t=j;
			}
		}
		v[t]=1;
		for(int j=1;j<=n;j++)
		{
			if(graph[t][j]!=INF)
				dis[j]=min(dis[j],dis[t]+graph[t][j]);
		}
	}
	cout<<dis[n]<<endl;
}
int main()
{
	memset(graph,INF,sizeof(graph));
	cin>>m>>n;
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b>>c;
		graph[a][b]=graph[b][a]=min(graph[a][b],c);
	}
	dijkstra();
	return 0;
}

标签:dist,int,graph,SPFA,Dijkstra,Floyd,INF,dis
From: https://www.cnblogs.com/KAI040522/p/17836556.html

相关文章

  • 【科研相关知识】Dijkstra算法
    Dijkstra算法相关背景知识历史来源exampleDijkstra算法相关背景知识Dijkstra算法是解决图论中的最短路径问题而最短路径问题是在图中找到两个节点之间的最短路径在导航中确定路线最短,在网络中路由器使用Dijkstra算法确定最短路径和转发端口。最短路径算法有Dijkstra算......
  • 【学习笔记】dijkstra
    一、dijkstra1.定义&作用很简单。一个单源最短路算法。2.思想&实现我觉得sm的图已经够了。二、堆优化dijkstra1.先来认识一下proirity_queue2.如何使用proirity_queue对dijkstra优化?每一步,我们都需要找到\(d\)值最小的节点(即\(......
  • 【学习笔记】spfa
    一、spfa模板:voidspfa(intx){ for(inti=1;i<=n;i++) vis[i]=0,dis[i]=inf; dis[1]=0,f[1]=1; q.push(1); while(!q.empty()) { intt=q.front(); q.pop(); vis[t]=0; for(inti=first[t];i;i=e[i].next) { intto=e[i].to; if(dis[t]+e[i].v<......
  • FFmpeg 7.0 “Dijkstra” 发布
    FFmpeg7.0“Dijkstra”发布来源:OSCHINA编辑: 白开水不加糖2024-04-0710:11:00 2国产数据库圈,为啥那么多水货?”FFmpeg7.0“Dijkstra”现已发布。此版本以荷兰计算机科学家EdsgerW.Dijkstra的名字命名,一些值得注意的变化包括原生VVC解码器(目前处于......
  • floyd求路径
    #include<iostream>#include<stdio.h>#include<algorithm>#include<string>#include<cmath>#include<string.h>#defineR(x)x=read()#defineFor(i,j,n)for(inti=j;i<=n;++i)usingnamespacestd;inlin......
  • DIjkstra进阶模板 路径记录 按权重(结点数最小等)记录
    structDIJ{usingi64=longlong;usingPII=pair<i64,i64>;vector<i64>dis,path,node;vector<vector<array<int,3>>>G;intn;DIJ(){}DIJ(intn):n(n){node.resize(n+1,1);......
  • Pintia 天梯地图 dijkstra进阶
    7-14天梯地图-SMU2024spring天梯赛3(补题)(pintia.cn)dijkstra进阶做法,包含路径记录,以及按权重统计路径条件等;不过最开始我一直将优先队列开的最大堆,但是一直过不了自己的例子,后来改成最小堆并且路径值改成负数存进去就对了,再后来我发现改成最大堆也可以,不过要把......
  • P8312 [COCI2021-2022#4] Autobus floyd最短路
    [P8312COCI2021-2022#4]Autobus-洛谷|计算机科学教育新生态(luogu.com.cn)思路:nnn数据范围很小可以用Floyd算法。注意:最多坐......
  • Floyd算法 【多源最短路】模板
    B3647【模板】Floyd-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>usingnamespacestd;constintN=1e2+10;constintinf=0x3f3f3f;intn,m;intg[N][N];voidfloyd(){for(intk=1;k<=n;k++){for(inti=1;i<=n;i++)......
  • Dijkstra邻接矩阵板子
    constintN=510;//节点个数intn;intg[N][N];//图intdist[N];//距离boolst[N];//判断点是否访问过intdijkstra(ints)//s表示起点,求s到任意点的最短距离{memset(dist,0x3f,sizeofdist);dist[s]=0;for(inti=0;i<n;i++){......