Dijkstra求最短路的基本思路是贪心算法,求解单源最短路。
适用于求解正权边。
算法的基本原理可以自行查看。
这里讲解两种求最短路的方法:
(1)、朴素算法
朴素算法的时间复杂度为O(n2),适用于稠密图,用邻接矩阵来存图,并且可以处理自环和重边。
给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
输入格式
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。
数据范围
1≤n≤500 1≤n≤500,1≤m≤105 1≤m≤105,
图中涉及边长均不超过10000。
输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3
模板代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510;
int n,m;
int q[N][N];
int d[N];
bool f[N];
int dj()
{
memset(d,0x3f,sizeof d);
d[1]=0;
for(int i=0;i<n;i++)
{
int t=0;
for(int j=1;j<=n;j++)
if(!f[j]&&(t==0||d[t]>d[j])) t=j;
f[t]=1;
for(int j=1;j<=n;j++)
if(!f[j]) d[j]=min(d[j],d[t]+q[t][j]);
}
if(d[n]==0x3f3f3f3f) return -1;
return d[n];
}
int main()
{
memset(q,0x3f,sizeof q);
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
q[a][b]=min(c,q[a][b]);
}
int k=dj();
printf("%d\n",k);
return 0;
}
(2)、堆优化算法
Dijkstra朴素算法只能处理变数较小的情况,当边数较多时间复杂度会变得特别大,邻接表所需空间也会很大。
这里就可以用到堆优化,堆优化主要适用于稀疏图(稠密图用也没问题),也可以处理自环和重边。
堆优化主要是用优先队列来实现,用邻接表存图(邻接表可以自己写或者直接用vector),时间复杂度为O(m log n )。
模板题:
给定一个n个点m条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出1号点到n号点的最短距离,如果无法从1号点走到n号点,则输出-1。
输入格式
第一行包含整数n和m。
接下来m行每行包含三个整数x,y,z,表示存在一条从点x到点y的有向边,边长为z。
输出格式
输出一个整数,表示1号点到n号点的最短距离。
如果路径不存在,则输出-1。
数据范围
1≤n,m≤1.5×1051≤n,m≤1.5×105,
图中涉及边长均不小于0,且不超过10000。
输入样例:
3 3
1 2 2
2 3 1
1 3 4
输出样例:
3
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+10;
typedef pair<int,int> pii;
vector<pii>v[N];
int d[N];int n,m;
int dij()
{
memset(d,0x3f,sizeof d);
d[1]=0;
priority_queue<pii,vector<pii>,greater<pii> >q;//给pii排序时先排fist 其次second
q.push({0,1});
while(!q.empty())
{
pii t=q.top();
q.pop();
int ver=t.second,dis=t.first;for(int i=0;i<v[ver].size();i++)
{
pii y=v[ver][i];
if(dis+y.first<d[y.second])
{
d[y.second]=dis+y.first;
q.push({d[y.second],y.second});
}
}
}
if(d[n]==0x3f3f3f3f) return -1;
return d[n];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int a,b,x;
scanf("%d%d%d",&a,&b,&x);
v[a].push_back({x,b});
}
int k=dij();
printf("%d\n",k);
return 0;
}
这里用pair来存1到id距离和id,优先队列默认以pair first从小到大排序。