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;
    }
  • 相关阅读:
    产品经理之PRD详解(非原创)
    编写代码的「八荣八耻」- 以开关上线为荣,以自信编码为耻
    安装社区版git仓库
    【干货分享】大话团队的GIT分支策略进化史
    Android IPC机制(一)开启多进程
    使用adb命令通过IP地址连接手机
    一篇文章了解Github和Git教程-AndroidStudio上传Github教程
    sublime实现markdown浏览器预览
    idea上maven使用心得(三)——用pom.xml添加jar包
    idea解决Maven jar依赖冲突(四)
  • 原文地址:https://www.cnblogs.com/AK-ls/p/10614203.html
Copyright © 2011-2022 走看看