zoukankan      html  css  js  c++  java
  • 第k短路(Dijkstra & A*)

    最短路,即第1短路有很多种求法,SPFA,Dijkstra等,但第k短路怎么求呢?其实也是基于Dijkstra;因为Dijkstra用的是堆优化,这样保证每次弹出来的都是最小值,只是求最短路只是弹出一次就返回了,我们可以用Dijkstra弹出k个距离后再返回,这样根据弹出的先后顺序能够求出1~k短路

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    const int INF = 0x3f3f3f3f;
    const int MAXN = 5e5 + 100;
    const int MAXM = 3e3 + 10;
    
    inline int read() {
        int x = 0, ff = 1; char ch = getchar();
        while(!isdigit(ch)) {
            if(ch == '-') ff = -1;
            ch = getchar();
        }
        while(isdigit(ch)) {
            x = (x << 1) + (x << 3) + (ch ^ 48);
            ch = getchar();
        }
        return x * ff;
    }
    
    inline void write(ll x) {
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
    
    int n, m, k, v;
    ll ans, dist[110];
    int lin[MAXN], tot = 0;
    struct edge {
        int y, v, next;
    }e[MAXN];
    
    inline void add(int xx, int yy, int vv) {
        e[++tot].y = yy;
        e[tot].v = vv;
        e[tot].next = lin[xx];
        lin[xx] = tot;
    }
    
    void Dijkstra() {
        priority_queue < pair < int , int > > q;
        q.push(make_pair(0, 1));
        while(!q.empty()) {
            int x = q.top().second;
            int d = -q.top().first;
            q.pop();    
            if(x == n)  {
                dist[++v] = d;
                if(v == k + 1) return ;
            }
            for(int i = lin[x], y; i; i = e[i].next) {    
                y = e[i].y;
                ans = d + e[i].v;
                q.push(make_pair(-ans, y));
            }
        }
    }
    
    int main() {
        memset(dist, -1, sizeof(dist));
        n = read(); m = read(); k = read();
        for(int i = 1; i <= m; ++i) {
            int x,y,v;
            x = read(); y = read(); v = read();
            add(x, y, v);
        }
        Dijkstra();
        for(int i = 1; i <= k; ++i) {
            write(dist[i]);
            putchar('
    ');
        }
        return 0;
    }

    emmmmm, 还有一种更高级的算法, 先来回顾优先队列的BFS, 不断从堆中取出“当前代价最小” 的状态进行拓展。每个状态第一次从堆中取出时, 就得到了从初态到该状态的最小代价。然而, 一个状态当前最小, 不代表从该状态到目标状态代价就最小,但是优先队列BFS会先选择这个分支, 导致搜索量增大;

    所以, 我们能够想到, 设计一个函数, 计算从该状态到目标状态的代价的估计值, 仍然维护一个堆,把当前价值 + 估计价值最小作为拓展;估价函数原则是估价值 <- 实际值(不再证明。。。)

    在求第k短路时, 我们把最短路作为估价, 保证估价 <= 实际, 还能顺应实际的变化趋势

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    const int INF = 0x3f3f3f3f;
    const int MAXN = 5e5 + 100;
    const int MAXM = 3e3 + 10;
    
    template < typename T > inline void read(T &x) {
        x = 0; T ff = 1, ch = getchar();
        while(!isdigit(ch)) {
            if(ch == '-') ff = -1;
            ch = getchar();
        }
        while(isdigit(ch)) {
            x = (x << 1) + (x << 3) + (ch ^ 48);
            ch = getchar();
        }
        x *= ff;
    } 
    
    template < typename T > inline void write(T x) {
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    } 
    
    int n, m, s, t, k;
    int f[MAXN], vis[MAXN];
    int lin[MAXN], tot = 0, linc[MAXN], totc = 0;
    struct edge {
        int y, v, next;
    }a[MAXN], e[MAXN];
    
    struct node {
        int pos, f, dis;
        bool operator < (node a) const {
            return a.f + a.dis < f + dis; 
        } 
    };
    
    inline void add(int xx, int yy, int vv) {
        a[++tot].y = yy;
        a[tot].v = vv;
        a[tot].next = lin[xx];
        lin[xx] = tot;
    }
    
    inline void addc(int xx, int yy, int vv) {
        e[++totc].y = yy;
        e[totc].v = vv;
        e[totc].next = linc[xx];
        linc[xx] = totc;
    }
    
    void SPFA() {
        queue < int > q;
        memset(f, 0x3f, sizeof(f));
        memset(vis, false, sizeof(vis));
        q.push(t); 
        f[t] = 0;
        vis[t] = true;
        while(!q.empty()) {
            int x = q.front(); q.pop();
            vis[x] = false;
            for(int i = lin[x], y; i; i = a[i].next) {
                if(f[y = a[i].y] > f[x] + a[i].v) {
                    f[y] = f[x] + a[i].v;
                    if(!vis[y]) {
                        vis[y] = true;
                        q.push(y);
                    }
                } 
            }    
        }
    } 
    
    int astar() {
        priority_queue < node > q;
        if(f[s] == INF) return -1;
        int ts[MAXN];
        node tmp, h;
        h.pos = s; h.f = 0; h.dis = 0;
        q.push(h);
        while(!q.empty()) {
            node x = q.top(); q.pop();
            ts[x.pos]++;
            if(ts[x.pos] == k && x.pos == t) return x.dis;
            if(ts[x.pos] > k) continue;
            for(int i = linc[x.pos]; i; i = e[i].next) {
                tmp.pos = e[i].y;
                tmp.f = f[e[i].y];
                tmp.dis = x.dis + e[i].v;
                q.push(tmp);
            }
        }
        return -1;
    }
    
    int main() {
        read(n); read(m);
        for(int i = 1; i <= m; ++i) {
            int u, v, w;
            read(u); read(v); read(w);
            add(v, u, w);
            addc(u, v, w);
        }
        read(s); read(t); read(k);
        if(s == t) ++k;
        SPFA();
        write(astar());
        return 0;
    }
  • 相关阅读:
    UVA1349 Optimal Bus Route Design 最优巴士路线设计
    POJ3565 Ants 蚂蚁(NEERC 2008)
    UVA1663 Purifying Machine 净化器
    UVa11996 Jewel Magic 魔法珠宝
    NEERC2003 Jurassic Remains 侏罗纪
    UVA11895 Honorary Tickets
    gdb调试coredump(使用篇)
    使用 MegaCLI 检测磁盘状态并更换磁盘
    员工直接坦诚直来直去 真性情
    山东浪潮超越3B4000申泰RM5120-L
  • 原文地址:https://www.cnblogs.com/AK-ls/p/10614203.html
Copyright © 2011-2022 走看看