单元最短路径-Dijkstra算法 算法竞赛笔记
什么是单源最短路径问题
给定一张有向图,求dist数组,dist[i]是某个起点到,第i个点的最短距离。
Dijkstra算法流程
1.初始化dist[1]=0,其余点都为无穷大
2.找到最小的dist[i]并且节点i未被标记,标记i
3.扫描i的所有出边,如果能够更新dist数组,就更新
4.重复2~3步骤,知道所有的点,都被标记
适用范围
边权非负,因为:dist最小的值,一定不会被其他点更新,先用他去更新其他值一定会比用比他大的值更新其他值更好。
矩阵储存图实现
#include<iostream>
#include<cstring>
using namespace std;
int a[3010][3010],d[3010],n,m;
bool v[3010];
void dijkstra(){
memset(v,0,sizeof v);
memset(d,0x3f,sizeof d);
d[1] = 0;
for(int i = 1;i < n;i++){
int x = 0;
for(int j = 1;j <= n;j++){
if(!v[j]&&d[j]<=d[x]) x = j;
}
v[x]=1;
for(int y = 1;y<=n;y++){
d[y] = min(d[y],d[x]+a[x][y]);
}
}
}
int main(){
int x,y,z;
cin>>n>>m;
memset(a,0x3f,sizeof a);
for(int i = 1;i <= n;i++) a[i][i] = 0;
for(int i = 0;i < m;i++){
cin>>x>>y>>z;
a[x][y] = min(a[x][y],z);
}
dijkstra();
for(int i = 1;i <= n;i++) cout<<d[i]<<" ";
cout<<endl;
}
邻接表储存图实现
#include<iostream>
#include<cstring>
using namespace std;
const int N = 510,M = 100010;
int h[N],r[M],v[M],e[M],tot,d[N],n,m;
bool vis[N];
void init(){
tot = 1;
}
void add(int x,int y,int z){
r[tot] = h[x],v[tot] = y,e[tot] =z,h[x] = tot,tot++;
}
void dijkstra(){
memset(d,0x3f,sizeof d);
d[1] = 0;
for(int i = 1;i < n;i++){
int x = 0;
for(int j = 1;j <= n;j++)
if(!vis[j]&&d[j]<=d[x]) x = j;
vis[x] = true;
for(int j = h[x];j;j = r[j])
d[v[j]] = min(d[v[j]],d[x]+e[j]);
}
}
int main(){
int x,y,z;
cin>>n>>m;
init();
for(int i = 0;i<m;i++){
cin>>x>>y>>z;
add(x,y,z);
}
dijkstra();
for(int i = 1;i <= n;i++)
cout<<d[i]<<" ";
}
有限队列优化Dijkstra
void dijkstra(){
memset(d,0x3f,sizeof d);
memset(vis,false,sizeof vis);
d[1] = 0;
priority_queue<pair<int,int> > q;//第一个元素是d,
q.push({0,1});
while(q.size()){
int x = q.top().second;q.pop();
if(vis[x]) continue;
vis[x] = true;
for(int j = h[x];j;j = r[j]){
if(d[v[j]]>d[x]+e[j]){
d[v[j]]=d[x]+e[j];
q.push({-d[v[j]],v[j]});//采用延迟标记的方法,不直接删除
}
}
}
}

浙公网安备 33010602011771号