单源最短路径

背景知识

  1. 图简介:图由节点和边组成,边有方向的图称为有向图,边没有方向的图称为无向图,最短路径算法里可以把无向图视为双向连接的有向图。 边有权重的图称为有权图,边没有权重的图称为无权图,无权图可以视为边的权重均为1的图。
  2. 单源点最短路径:给定图中的一个节点,求该节点到其他所有节点的最短路径。

Dijkstra算法

Dijikstra算法就是为了解决单元最短路径问题。可以解决有向正权图和无向图,为什么不可以是负权图呢?我们后面再做讨论。
一.核心思想
我们设G=(V,E)为一个带权有向图,我们可以把图中的节点分为两组:

  • 一组为已经求出最短路径的顶点集合S,如果后续求出来一条最短路径那就把端点加入到集合S中,
  • 二组为未确定最短路径的节点集合U。
    同时,我们定义一个dist[i] 用来表示 从i节点到源点的最小距离。

二.步骤

  1. 初始化,源点加入到S中, 其他节点加入到U中。将起始节点start的所有可达节点的最短路径长度置为edge(start, arriveNode),
  2. 遍历curr可以达到的集合U中的节点(u),更新过程中:
    如果dist[curr] + edge(curr,u) < dist[u],那么更新dist[u] = dist[curr] + edge(curr,u)
    最后找到U集合中距离源点路径最短的节点,即我们上面所求的dist[u]值最小节点u,加其入到S集合中,然后将 u 节点作为下次遍历的 curr 节点(也就是这个u节点是我们S集合中距离源点最长的节点了)
  3. 重复步骤2
    参考过程:
    image.png

    三.负权图无法判定的原因
    image.png

    上图中,显然0-1-1是我们的最短路径,在此算法中第一步,我们按照步骤寻找U集合里面的最小路径,将节点0,2分别添加到S集合中,于是我们的curr节点变为2,然后我们把1节点加入,所以算法结束答案计算0-2的最短路径应该是2而不是1。综上,Dijkstra算法不适合于边权值为负值的图。
    四.有向图和无向图代码
    我们根据一个题目来理解用法:
    image.png
#include <iostream>
#include <climits>
using namespace std;
int n, m, start, endIndex;
int ways[2501][2501];           
long long dist[2501];
bool visited[2501] = {false};
int main(){
    cin >> n >> m >> start >> endIndex;
    //路径默认为极大值
    for (int i = 0; i <= 2500; i++)//init
        for (int j = 0; j <= 2500; j++)
            ways[i][j] = INT_MAX;
    fill(dist, dist + 2501, INT_MAX);
    //填充路径
    for(int i = 0; i < m; i++){
        int from , to, value;
        scanf("%d %d %d",&from, &to, &value);
        if(value < ways[from][to]){
            ways[from][to] = ways[to][from] = value; 
        }
    }
    //初始化
    dist[start] = 0;
    int min_value_index, min_value; //定义每次从集合U中最小路径下标以及最小路径
    while(true){
        min_value_index = -1;
        min_value = INT_MAX;
        //找到集合U中的最小路径下标和最小路径
        for(int i = 1; i <= n; i++){
            if(!visited[i] && min_value > dist[i]){
                min_value_index = i;
                min_value = dist[i];
            }
        }
        //如果所有节点都已经遍历过找到最小路径长度,那么直接跳出。
        if(min_value_index == -1) break;
        //将min_value_index元素加入到visited中
        visited[min_value_index] = true;
        //遍历更新U集合中每一个节点的距离
        for(int i = 1; i <= n; i++){
            if(!visited[i]){
                dist[i] = min(dist[i], dist[min_value_index] + ways[min_value_index][i]);
            }
        }
    }
    // print answer
    cout << dist[endIndex];
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,440评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,814评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,427评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,710评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,625评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,511评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,162评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,311评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,262评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,278评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,989评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,583评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,664评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,904评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,274评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,856评论 2 339

推荐阅读更多精彩内容