zoukankan      html  css  js  c++  java
  • 谈一谈Dijkstra

    dijkstra呢是最短路三大算法之一。很多人都觉得不如spfa,但是这两者在跑稠密图时,dijkstra有奇效

    在讲之前先说一说食用方法:

    适用于有向的无负权值的图。

    样例飘过

    6 9 1      //n个点,m条边,以s为起点
    1 3 3
    1 6 10
    3 6 5
    4 3 7
    1 4 4
    4 2 5
    5 2 4
    4 5 6
    3 5 6
    

      

    0 9 3 4 9 8
    

      

    上面这组样例我们让他更直观一些

    神图警报,请开启护眼模式

    真心累

    首先我们应该知道dijkstra的核心思想是贪心。

    定义一个$dis$数组,$dis[i]$表示从起点到i节点的距离,我们在程序一开始的时候把dis全部赋值成INF,

    只把dis[s]赋值成0,(因为s->s == 0),这时候我们需要定义一个bool行的数组book,book[i]表示节点是否被访问过。

    那么接下来就进入核心部分了。

    我们每次从所有的节点中找一个dis值最小的,当让我们知道第一次肯定会找到s,然后以这个点为节点向外扩展,如果在已知的边的基础上可以找到更短的到某一个点的路径,那么就将这个路径更新。

    这么说可能有点抽象,那么让我们看点实在的

    上图

    第一次找到了dis值最小的1号节点向外扩展,那么现在dis数组的值为

    $dis[1] = 0, dis[2] = INF, dis[3] = 3, dis[4] = 4, dis[5] = INF, dis[6] = 10$

    记得要把book[1]变成1,代表已经访问过。

    接下来进行第二次扩展,这时候由于dis[1]我们已经访问过,所以接下来就会选择3号节点进行扩展

    如图

    从3号节点出去的边可以连到5和6,连5时毫无疑问会更新,但是再连6时,我们发现dis[6]已经扩展了一次,那么怎么办呢,很明显,从1走到3再走到6的话总路程为dis[3]加上3到6的路程,共为8,比现有的dis[6]要小,所以我们就要再更新dis[6] = 8;

    通过这么一次次的更新,我们就能把这张图的最短路跑完,注意是单源最短路。

    说了这么多我们来看下代码,但是我这个代码有个很玄学的地方,就是建边的时候我写的是用数组实现的邻接链表,但是原理是和结构体实现的邻接链表相同,大家将就着看,如果看不懂那就参考一下下面这篇文章

    【坐在马桶上看算法】算法8:巧妙的邻接表(数组实现)

    这里讲的非常的详细,我当初就是看的这里。


    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define MAXN 500008
    #define INF  2147483647
    #define maxn 10008
    
    using namespace std;
    
    int n, m, s;
    int next[MAXN], first[MAXN];
    int u[MAXN], v[MAXN], w[MAXN];
    int dis[maxn];
    bool book[MAXN];
    
    int main() {
    	scanf("%d%d%d", &n, &m, &s);
    	for(int i=1; i<=n; i++) {
    		dis[i] = INF;
    	}
    	dis[s] = 0;
    	memset(first, -1, sizeof(first));
    	for(int i=1; i<=m; i++) {
    		scanf("%d%d%d", &u[i], &v[i], &w[i]);
    		next[i] = first[u[i]];
    		first[u[i]] = i;
    	}
    	for(int i=1; i<n; i++) {
    		int minn = INF, x;
    		for(int j=1; j<=n; j++) {
    			if(dis[j] < minn&&book[j] == 0) {
    				minn = dis[j];
    				x = j;
    			}
    		}
    		book[x] = 1;
    		int k = first[x];
    		while(k != -1) {
    			if(dis[v[k]] > dis[u[k]]+w[k]) {
    				dis[v[k]] = dis[u[k]]+w[k];
    			}
    			k = next[k];
    		}
    	}
    	for(int i=1; i<=n; i++) {
    		printf("%d ", dis[i]);
    	}
    }
    

      

  • 相关阅读:
    MSSQL大量数据时,建立索引或添加字段后保存更改超时该这么办
    POJ 3261 Milk Patterns (后缀数组)
    POJ 1743 Musical Theme (后缀数组)
    HDU 1496 Equations (HASH)
    694. Distinct Substrings (后缀数组)
    POJ 1222 EXTENDED LIGHTS OUT (枚举 或者 高斯消元)
    POJ 1681· Painter's Problem (位压缩 或 高斯消元)
    POJ 1054 The Troublesome Frog (hash散列)
    HDU 1716 排列2
    HDU 4405 Aeroplane chess (概率DP & 期望)
  • 原文地址:https://www.cnblogs.com/bljfy/p/8835398.html
Copyright © 2011-2022 走看看