单元最短路径-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]});//采用延迟标记的方法,不直接删除
            }
        }
    }
}
posted @ 2020-04-07 17:28  dachengqian  阅读(427)  评论(0)    收藏  举报