Dijkstra算法 笔记与思路整理

该文章可能存在硬伤与不妥,不能作为教程阅读。(因为我真的鶸

 

Dij作为单源最短路算法,需要先确定一个起点。Dij的函数主体为维护每个节点的dis和vis两个变量。dis表示该点距离起点的最短路权值和,vis存储该点是否被访问过

设点数为n,无向边数为m,则要进行n次循环,每次循环中找出一个dis最小且vis不为真的点进行松弛操作。

这里抄一段百科:

松弛操作是指对于每个顶点v∈V,都设置一个属性g[v],用来描述从源点s到v的最短路径上权值的上界,称为最短路径估计(shortest-path estimate)。

松弛操作主要代码:

if(dis[g[i].to] > g[i].val + curr.dis)
    dis[g[i].to] = g[i].val + curr.dis;

然后就是优化:

  (1)判断最小值的循环可用优先队列优化

  (2)使用优先队列后可以直接判断堆中是否剩余元素来循环

  (3)使用链表存储图,松弛操作只遍历相关的边

模板:

#include <bits/stdc++.h>
#define maxn 10010
#define maxm 10010
using namespace std;

struct edge{
    int to, val, next;
};
edge g[maxm];
int first[maxn], edge_cnt = 0;

struct node{
    int pos, dis;
};
priority_queue<node> q;
bool operator<(const node a, const node b){
    return a.dis > b.dis;
}
int dis[maxn], vis[maxn];

int n, m;
void in_put(){
    scanf("%d%d", &n, &m);    //n nodes, m edges
    for(int i=0; i<m; i++){
        int f, t, val;
        scanf("%d%d%d", &f, &val, &t);
        g[edge_cnt] = (edge){t, val, 0};
        g[edge_cnt].next = first[f];
        first[f] = edge_cnt;
        edge_cnt ++;
    }
}
void dijkstra(int start){
    vis[start] = 1;
    dis[start] = 0;
    q.push((node){start, dis[start]});
    while(q.size()){
        node curr = q.top();
        q.pop();
        int from = curr.pos;
        for(int i = first[from]; i ; i = g[i].next){
            if(dis[g[i].to] > g[i].val + curr.dis){
                dis[g[i].to] = g[i].val + curr.dis;
                q.push((node){g[i].to, dis[g[i].to]});
            }
        }
    }
    
}
int main(){
//    freopen(".in", "r", stdin);
//    freopen(".out", "w", stdout);
    memset(dis, 0x3f, sizeof(dis));
    in_put();
    dijkstra();
    return 0;
}
posted @ 2019-08-15 09:55  mzWyt  阅读(668)  评论(0编辑  收藏  举报