最短路

最短路

  • 1.单源最短路
    • 所有边权都是正的
      • 朴素Dijkstra O( n^2 )
      • 堆优化Dijkstra O(mlogn)
      • 存在负权边
        • Bellman-Ford O(mn)
        • SPFA 一般O(m),最坏O(mn)
  • 2.多源汇最短路 Floyd算法 O(n^3)

朴素Dijkstra

  • 1.初始化距离,dis[1]=0,dis[i]=INF;
  • 2.遍历集合,找到不在s(当前已确定最短距离的点)中的距离最近的点,更新当前其他点的距离;
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 510;

int m, n;
int g[N][N], dist[N];
bool st[N];

int dijkstra() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    for (int i = 0; i < n; ++i) {
        int t = -1;
        for (int j = 1; j <= n; ++j) {
            if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
        }
        st[t] = true;

        for (int j = 1; j <= n; ++j) {
            dist[j] = min(dist[j], dist[t] + g[t][j]);
        }
    } 
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}


int main() {
    cin >> n >> m;

    memset(g, 0x3f, sizeof g);
    
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = min(g[a][b], c);
    }
    cout << dijkstra() << endl;
    return 0;
}

堆优化Dijkstra

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n, m;
int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool st[N];

void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

int dijkstra() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0, 1});
    while (heap.size()) {
        auto t = heap.top();
        heap.pop();
        
        int ver = t.second, distance = t.first;
        if (st[ver]) {
            continue;
        } 
        for (int i = h[ver]; i != -1; i = ne[i]) {
            int j = e[i];
            if (dist[j] > distance + w[i]) {
                dist[j] = distance + w[i];
                heap.push({dist[j], j});
            }
        }
    }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main () {
    cin >> n >> m;
    memset(h, -1, sizeof h);
    
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
    }
    
    cout << dijkstra() << endl;
    
    return 0;    
}

Bellman-Ford

  • n次迭代,循环所有边a、b、w,更新距离;

  • dist[b] <= dist[a] + w;
    
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 510, M = 10010;
int n, m, k;
int dist[N], backup[N];

struct {
    int a, b, w;
} edges[M];

int bellman_ford() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;    
    for (int i = 0; i < k; ++i) {
        memcpy(backup, dist, sizeof dist);
        for (int j = 0; j < m; ++j) {
            int a = edges[j].a, b = edges[j].b, w = edges[j].w;
            dist[b] = min(dist[b],backup[a] + w);
        }
    }
    if (dist[n] > 0x3f3f3f3f / 2) return -1;
    return dist[n];
}

int main() {
    cin >> n >> m >> k;
    
    for (int i = 0; i < m; ++i) {
        int a, b, c;
        cin >> a >> b >> c;
        edges[i] = {a, b, c};
    }
    int t = bellman_ford();
    if (t == -1) printf("impossible\n");
    else printf("%d\n", t);
    return 0;
}

SPFA

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
const int N = 100010;
using namespace std;
int n, m, h[N], e[N], ne[N], w[N], dist[N], idx;
bool st[N];


void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; 
}

int spfa() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    
    queue<int> q;
    q.push(1);
    st[1] = true;
    
    while (q.size()) {
        int t = q.front();
        q.pop();
        st[t] = false;
        
        for (int i = h[t]; i != -1; i = ne[i]) {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) {
                dist[j] = dist[t] + w[i];
                if (!st[j]) {
                    q.push(j);
                    st[j] = true;
                }
            }
        }
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main() {
    cin >> n >> m;
    memset(h, -1, sizeof h);
    
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
    }
    int t = spfa();
    if (t == -1) puts("impossible");
    else cout << t << endl;
    return 0;
}

Floyd

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 210, INF = 1e9;
int n, m, q;
int d[N][N];

void floyd() {
    for (int k = 1; k <= n; ++k) {
        for (int i = 1; i <= n ;++i) {
            for (int j = 1; j <= n; ++j) {
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
}

int main() {
    cin >> n >> m >> q;
    for (int i = 1; i <= n ; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (i == j) d[i][j] = 0;
            else d[i][j] = INF;
        }
    }
    
    while (m--) {
        int a, b, w;
        cin >> a >> b >> w;
        d[a][b] = min(d[a][b], w);
    }
    floyd();
    
    while (q--) {
        int a, b;
        cin >> a >> b;
        if (d[a][b] > INF / 2) printf("impossible\n");
        else printf("%d\n", d[a][b]);
    }
    
    return 0;
}



posted @ 2020-03-18 23:37  景云ⁿ  阅读(90)  评论(0编辑  收藏  举报