图◆单源最短路径 | Dijkstra

  • 单源最短路算法总结 by liuchuo大佬
  • 单源最短路 from北大-算法设计与分析此视频的下一p是Dijkstra算法正确性的证明

Dijkstra算法的策略

  • 全部结点V
  • 源点src
  • 集合S:目前已达结点集合,即已经确定最短路的结点的集合 (实现时,用visited数组维护),将结点x加入集合S即将visited【x】置为true。
  • distance【i】:从src出发,经由集合S内的点,到结点i的最短路径长度
  1. 初始化
    将src加入到S,distance【src】= 0;其他结点的distance为INF
  2. 循环(n次,每次把一个点加入集合S)
    2.1 找到 V-S 中距离src距离最短的点x,并将点x加入集合S
    2.2 以点x为中介,更新集合S中点的distance(若有更短的路径,覆盖原有的)

正确性证明



摘自北大算法公开课PPT

1030 Travel Plan (30 分)

友好的最短路模板题

#include 
#include 
#include 

#define INF 0x3fffffff
using namespace std;
int nn, mm, from, to, pre[501];
struct Highway {
    int dis = INF, cost = INF;
};
int dist[501], cost[501] = {0};
Highway graph[501][501];

void Dijkstra(int src) {
    bool visited[501] = {false};
    fill(dist, dist + 501, INF);
    fill(cost, cost + 501, INF);
    dist[src] = 0, cost[src] = 0;
    for (int i = 0; i < nn; ++i) {
        int min_dist = INF, curr = -1;
        for (int j = 0; j < nn; ++j) {
            if (!visited[j] && dist[j] < min_dist) {
                min_dist = dist[j];
                curr = j;
            }
        }
        if (curr != -1) {
            visited[curr] = true;
            for (int j = 0; j < nn; ++j) {
                if (!visited[j] && graph[curr][j].dis != INF) {
                    int new_dist = dist[curr] + graph[curr][j].dis;
                    if (new_dist < dist[j]) {
                        dist[j] = new_dist;
                        cost[j] = cost[curr] + graph[curr][j].cost;
                        pre[j] = curr;
                    } else if (new_dist == dist[j] && cost[j] > cost[curr] + graph[curr][j].cost) {
                        cost[j] = cost[curr] + graph[curr][j].cost;
                        pre[j] = curr;
                    }
                }
            }
        } else return;
    }
}

int main() {
    scanf("%d%d%d%d", &nn, &mm, &from, &to);
    int v1, v2, dis, cc;
    for (int i = 0; i < mm; ++i) {
        scanf("%d%d%d%d", &v1, &v2, &dis, &cc);
        if (graph[v1][v2].dis > dis) {
            graph[v1][v2].dis = graph[v2][v1].dis = dis;
            graph[v1][v2].cost = graph[v2][v1].cost = cc;
        }
    }
    Dijkstra(from);
    stack res;
    int curr = to;
    while (curr != from) {
        res.push(curr);
        curr = pre[curr];
    }
    printf("%d", from);
    while (!res.empty()) {
        printf(" %d", res.top());
        res.pop();
    }
    printf(" %d %d", dist[to], cost[to]);
    return 0;
}

1003 Emergency (25 分)

真 的 惨 ,看了半天半年前自己贴在上的写法。一行一行对照,终于发现错哪了。从前就是不知道总结,就会贴代码,才凉凉了吧。。。。。。
  • 最短路径条数:应当继承当前pre的最短路径条数,而不是++或赋值为1☠️
⚠️路径条数的更新,这是❌的
  • 题目中没有说明两个结点之间最多只有一条路,最好用邻接矩阵存储,方便直接存两点间直接路径中最短的。
  • Dijkstra过程中break要谨慎,或者干脆就loop N次就好惹‍♀️
#include 
#include 
#include 

using namespace std;
const int INF = 0x3fffffff;
int nn, mm, src, final, cnt_path[505] = {0}, gathering[505] = {0};
int teams[505];
int graph[505][505];

void dijkstra(int root) {
    bool visited[505] = {false};
    int dist[505];
    fill(dist, dist + nn, INF);
    dist[root] = 0;
    cnt_path[root] = 1;
    gathering[root] = teams[root];
    for (int i = 0; i < nn; ++i) {
        int min_dist = INF, index = -1;
        for (int j = 0; j < nn; ++j) {
            if (!visited[j] && dist[j] < min_dist) {
                index = j;
                min_dist = dist[j];
            }
        }
        if (index != -1) {
            visited[index] = true;
            for (int j = 0; j < nn; ++j) {
                if (!visited[j] && graph[index][j] != INF) {
                    int new_dist = dist[index] + graph[index][j];
                    if (new_dist == dist[j]) {
                        cnt_path[j] += cnt_path[index];
                        gathering[j] = max(gathering[j], gathering[index] + teams[j]);
                    } else if (new_dist < dist[j]) {
                        dist[j] = new_dist;
                        cnt_path[j] = cnt_path[index];
                        gathering[j] = gathering[index] + teams[j];
                    }
                }
            }
            // if (index == final) break; 等长路径呢? break需谨慎!!
        } else {
            printf("ERROR. NOT CONNECTED.\n");
            break;
        }
    }
}

int main() {
    scanf("%d%d%d%d", &nn, &mm, &src, &final);
    for (int i = 0; i < nn; ++i) {
        scanf("%d", &teams[i]);
    }
    fill(graph[0], graph[0] + 505 * 505, INF);
    int v1, v2, weight;
    for (int i = 0; i < mm; ++i) {
        scanf("%d%d%d", &v1, &v2, &weight);
        if (graph[v1][v2] > weight) {
            graph[v1][v2] = graph[v2][v1] = weight;
        }
    }
    dijkstra(src);
    printf("%d %d\n", cnt_path[final], gathering[final]);
    return 0;
}

你可能感兴趣的:(图◆单源最短路径 | Dijkstra)