第k短路

Posted DearDongchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第k短路相关的知识,希望对你有一定的参考价值。

http://acm.pku.edu.cn/JudgeOnline/problem?id=2449 

有向图上求两点st, ed间的第k短的路径

emmm......

朴素的想法就是priority_queue,从原点出发向外探索,当取出终点k次时就得到第k短路

类似“bfs”的思想,缺陷是越往后状态数越多

改进一下,这里有个A*算法,比果体的搜索要好

在A*里面我们通过优先展开到ed近的状态,使搜索方向靠近答案,而不是一层一层全都展开

估价函数f=g+h f是估计的st到ed的距离,g是到达当前点已经点的花费,h是预计剩下的花费

h如果完全为真实值 那搜索就会笔直朝向答案前进没有浪费,如果h不那么准确,emmm问题不大,只是会晚点找到答案

我们表面上说h差不多就行,然而我们都知道,h的设计很重要

在这里h可以取当前点的距离到ed距离 通过反向建边,从ed跑一遍dijkstra可以预处理出距离数组

反向建边值得好好体会,边就在那里,只是head和next的连接一正一反

还有个细节就是st==ed时给k++,不然还没移动呢就有一次取出的计数了

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
// f = g + h;
const int maxn = 1e3+7, maxm = 1e5+7, INF = 0x3f3f3f3f;
int head[maxn], rhead[maxn], vis[maxn], d[maxn], cur;
struct edge{
    int rv, v, w, nxt, rnxt;
    edge(){}
    edge(int rv, int v, int w, int nxt, int rnxt):rv(rv), v(v), w(w), nxt(nxt), rnxt(rnxt){}
}e[maxm];
typedef pair<int, int>pi;
struct state{
    int g, h, v;// g cost h pending
    state(){}
    state(int g, int h, int v):g(g), h(h), v(v){}
    bool operator < (const state tmp)const{
        return g + h > tmp.g + tmp.h;
    }
};// greater<state> not defined
void addedge(int u, int v, int w){
    e[cur] = edge(u, v, w, head[u], rhead[v]);
    head[u] = cur;
    rhead[v] = cur++;
}
void dijkstra(int st){// distance from "st"
    memset(d, INF, sizeof(d));
    memset(vis, 0, sizeof(vis));
    priority_queue<pi, vector<pi>, greater<pi> >P;
    d[st] = 0;
    P.push(make_pair(0, st));
    while(!P.empty()){
        pi x = P.top();
        P.pop();
        int u = x.second, dis = x.first;
        if(vis[u])
            continue;
        vis[u] = 1;
        for(int i = rhead[u]; ~i; i = e[i].rnxt){
            int rv = e[i].rv, w = e[i].w, len = dis+w;
            if(d[rv] > len){
                d[rv] = len;
                P.push(make_pair(d[rv], rv));
            }
        }
    }
}
int Astar(int st, int ed, int k){
    if(st == ed)
        k++;
    if(d[st] == INF)
        return -1;
    priority_queue<state>P;
    P.push(state(0, d[st], st));
    while(!P.empty()){
        state x = P.top();
        P.pop();
        int g = x.g, u = x.v;
        if(u == ed){
            if(k > 1)
                k--;
            else
                return g;
        }
        for(int i = head[u]; ~i; i = e[i].nxt){
            int v = e[i].v, w = e[i].w;
            P.push(state(g+w, d[v], v));
        }
    }
    return -1;
}
int main(){
    int n, m;
    while(~scanf("%d%d", &n, &m)){
        cur = 0;
        memset(head, -1, sizeof(head));
        memset(rhead, -1, sizeof(rhead));
        while(m--){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addedge(u, v, w);
        }
        int st, ed, k;
        scanf("%d%d%d", &st, &ed, &k);
        dijkstra(ed);
        printf("%d\n", Astar(st, ed, k));
    }
    return 0;
}

 

以上是关于第k短路的主要内容,如果未能解决你的问题,请参考以下文章

poj 2449 Remmarguts' Date 第K短路

poj2449 k短路问题

A*算法

次短路 第K短路

A*算法的认识与求第K短路模板

第k短路