Dijkstra算法
从起点到终点求最短路 — 使用要求权值为正
1、求短路I
https://www.acwing.com/problem/content/851/
//题目 点数 500 边数 1e5
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510,M = 1e5+10;
//时间复杂度O(n^m)
int n,m;
//邻接矩阵
int a[N][N];
bool vis[N];//记录已经遍历的点
//记录起点到某点的最短路径
int d[N];
int dijkstra(){
d[1]=0;
for(int i=1;i<=n;++i){
int t = -1;
for(int j=1;j<=n;++j){
if(!vis[j]&&(d[t]>d[j]||t==-1)){
//找没有遍历的点 && 对于起点来说最短的点
t=j;
}
}
vis[t]=true;
for(int j=1;j<=n;++j){
//更新d中值
//更新起点到j点最短距离
d[j] = min(d[j],d[t]+a[t][j]);
}
}
if(d[n]>=0x3f3f3f3f) return -1;
return d[n];
}
int main(){
memset(a,0x3f,sizeof a);
memset(d,0x3f,sizeof d);
cin>>n>>m;
int x,y,z;
for(int i=0;i<m;++i){
cin>>x>>y>>z;
//可能出现重边,取最短的那条
a[x][y]=min(a[x][y],z);
}
cout<<dijkstra();
return 0;
}
2、求最短路II
https://www.acwing.com/problem/content/852/
数据范围 1e5 时间复杂度O(n^2) 超时!
优化思路:
1、循环每个点
2、每次找距离起点最短距离的点
3、进行更新
采用优先队列 优化2
采用邻接表 优化3
优化后时间复杂度 O(mlogn)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N =1e6;
int n,m;
int d[N];
bool vis[N];
typedef pair<int,int>PII;
//构建邻接表
int e[N],ne[N],w[N],h[N],idx;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra(){
d[1]=0;
//根据距离来排--从小到大
priority_queue<PII,vector<PII>,greater<PII>>q;
//pair 根据first来排序
q.push({0,1});//距离 结点
while(q.size()){
auto t = q.top();
q.pop();
//类似上面的 t
int k = t.second,distance=t.first;
//需要判断---不然超时
if(vis[k]) continue;
vis[k] = true;
//进行更新
for(int i=h[k];i!=-1;i=ne[i]){
int j = e[i];
//如果遍历过,跳过
if(vis[j]) continue;
//w[i]存储的是此时结点j的权值
//进行更新
if(d[j]>d[k]+w[i]){
d[j]=d[k]+w[i];
q.push({d[j],j});
}
}
}
if(d[n]>=0x3f3f3f3f) return -1;
return d[n];
}
int main(){
memset(h,-1,sizeof h);
memset(d,0x3f,sizeof d);
int x,y,z;
cin>>n>>m;
for(int i=0;i<m;++i) {
cin>>x>>y>>z;
add(x,y,z);
}
cout<<dijkstra();
return 0;
}