Dijkstra
核心思想
遍历每一个点,找到离点最近的点
类似于bfs,把该点可以拓展的点都遍历一遍,找到距离最近的且没有被取过(被遍历过)的点,然后用这个点来更新其他的点
核心代码
//除1号结点外,其他均初始为无穷大
memset(dist,0x3f,sizeof dist);
dist[1]=0;
//这里进行n次迭代,是为了把n个点都按照距离从小到大的顺序放入st
for(int i=0;i<n;i++){
// 便于更新第一个点
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
//将t加到已经取过的点中
st[t]=true;
//用t更新其他点的距离
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
//路径不存在
if(dist[n]==0x3f3f3f3f) return -1;
else return dist[n];
以下代码的具体流程:
for(int j=1;j<=n;j++) //用t更新其他点的距离
dist[j]=min(dist[j],dist[t]+g[t][j]);
首先我们找点第一个点,假设这个点是第一个点,那么这个循环就不会被执行,因为这个t类似于中间点,
1 --> 2 dist = 10
1 --> t dist = 5
t --> 2 dist = 2
dist[2] = min(dist[2],dist[t] + g [t] [2]),其中g (t,2)代表 点 t 到点 2的距离
dist (t) 表示 起点 到 t 的距离
邻接矩阵实现 [题目链接][849. Dijkstra求最短路 I - AcWing题库
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;
const int N = 1e6+10;
int g[1010][1010];
int n,m;
bool st[N];
int dist[N];
void dijkstra(){
memset(dist,0x3f,sizeof(dist));
dist[1] = 0;
for (int i = 1;i <= n;i++){
int t = -1;
for (int j = 1;j <= n;j++){
if (!st[j] && (t == -1 || dist[t] > dist[j])){
t = j;
}
}
st[t] = true;
for (int j = 1;j <= n;j++){
dist[j] = min(dist[j],dist[t]+g[t][j]);
}
}
}
int main(){
memset(g,0x3f,sizeof(g));
cin >> n >> m;
for (int i = 1;i <= m;i++){
int a,b,c;
cin >> a >> b >>c;
g[a][b] = min(g[a][b],c);
}
dijkstra();
if (dist[n] == 0x3f3f3f3f)cout << -1 << endl;
else
cout << dist[n] <<endl;
}
链式前向星实现
链式前向星:
ll e[N],ne[N],h[N],w[N],idx;
//e[] 存放下一个节点
// ne[] 为下一个边的起点
// w[] 存放两条边之间的权重
// h[] 存放该节点
// idx 记录总的边数 相当于给每个边一个编号
void add(ll a,ll b,ll c){
//记录节点与a链接的节点b,点与点之间的权重为c
e[idx] = b;
w[idx] = c;
//下一个节点为h[],也就是
ne[idx] = h[a];
//更新h[a] 表示添加边的位置
h[a] = idx++;
}
朴素版
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
const int N = 1e6+10;
int n,m;
int dist[N];
bool st[N];
int e[N],ne[N],h[N],idx,w[N];
void add(int a,int b,int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
void dijkstra(){
memset(dist,0x3f,sizeof(dist));
dist[1] = 0;
for (int i = 1;i <= n; i++){
int t = -1;
for (int j = 1;j <= n;j++){
if (!st[j] && (t == -1 || dist[t] > dist[j])){
t = j;
}
}
st[t] = true;
//k是j的直达点,
//t是j到k的中间点
//二者取较小值
for (int j = h[t];j != -1;j = ne[j]){
int k = e[j];
dist[k] = min(dist[k],dist[t]+w[j]);
}
}
}
int main(){
memset(h,-1,sizeof(h));
cin >> n >> m;
for (int i = 1;i <= m; i++){
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
}
dijkstra();
if (dist[n] == 0x3f3f3f3f)cout << -1 << endl;
else cout << dist[n] << endl;
return 0;
}
堆优化 [题目链接](850. Dijkstra求最短路 II - AcWing题库)
#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N = 1e6+10;
int n,m,dist[N];
bool st[N];
int h[N],ne[N],e[N],w[N],idx;
void add(int a,int b,int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
void dijkstra(){
memset(dist,0x3f,sizeof(dist));
//通过有限队列对dij进行优化,每次取距离最近的点
priority_queue<PII,vector<PII>,greater<PII>>q;
dist[1] = 0;
//第一个参数是距离,第二是节点
q.push({0,1});
while (q.size()){
PII t = q.top();
q.pop();
int v = t.second,d = t.first;
if (st[v])continue;
st[v] = true;
for (int i = h[v];i != -1;i = ne[i]){
int j = e[i];
//如果距离大于,中间点加上一条边的距离那就把,距离更新并与点加入队列
if(dist[j] > d + w[i]){
dist[j] = d + w[i];
q.push({dist[j],j});
}
}
}
}
int main(){
memset(h,-1,sizeof(h));
cin >> n >> m;
for (int i = 1;i <= m;i++){
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
}
dijkstra();
if(dist[n]==0x3f3f3f3f)cout <<-1 << endl;
else cout << dist[n] << endl;
return 0;
}
[[849. Dijkstra求最短路 I - AcWing题库]: