zoukankan      html  css  js  c++  java
  • A*模板(求K短路)(POJ2449)

    A*是bfs的优化,IDA*是dfs的优化

    A*算法: 为启发式算法中很重要的一种,被广泛应用在最优路径求解和一些策略设计的问题中。而A*算法最为核心的部分,就在于它的一个估值函数的设计上:
    f(n)=g(n)+h(n) 其中f(n)是每个可能试探点的估值,它有两部分组成:一部分为g(n),它表示从起始搜索点到当前点的代价(通常用某结点在搜索树中的深度来表示)。另一部分,即h(n),它表示启发式搜索中最为重要的一部分,即当前结点到目标结点的估值,h(n)设计的好坏,直接影响着具有此种启发式函数的启发式算法的是否能称为A*算法。


    题目(代码和原题稍微不同):
    链接:POJ2449
    第一行为n个点,m条边,求第k短路。
    接下来m行,每行3个数,代表起点、终点、边权。

    输出第k短路的路径长度。

    解法:

    K短路的定义:假设从1出发,有M条长度不同的路径可以到达点N,则K短路就是这M条路径中第K小的路径长度。 以上所述,设f[n]为最终所求,则f(n)=g(n)+h(n);h(n)就是我们所说的‘启发式函数’,表示为重点t到其余一点p的路径长度,g(n)表示g当前从s到p所走的路径的长度。
    即:估价函数=当前值+当前位置到终点的距离

    Solution:
    (1)将有向图的所有边反向,以原终点t为源点,求解t到所有点的最短距离;
    (2)新建一个优先队列,将源点s加入到队列中;
    (3)从优先级队列中弹出f(p)最小的点p,如果点p就是t,则计算t出队的次数;
    如果当前为t的第k次出队,则当前路径的长度就是s到t的第k短路的长度,算法结束;
    否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先级队列;

    代码如下:

    #include<cstdio>
    #include<vector>
    #include<queue>
    using namespace std;
    
    const int inf = 999999999;
    const int maxn = 500000 + 5;
    int n, m, k, s, t;
    
    struct edge {
        int v, w;
    };
    vector<vector<edge>>a, b;
    vector<int>dis(maxn, inf);
    vector<bool>flag(maxn, false);
    
    //f(n)=g(n)+h(n)
    //估价函数=当前值+当前位置到终点的距离
    struct node {
        int id;///当前节点编号
        int f;//f表示经过当前节点的最短路
        int g;//g表示S->当前节点的最短路
        node(int id = 0, int f = 0, int g = 0) :id(id), f(f), g(g) {}
        bool operator <(const node &a)const {//估价函数值大或者距初始点最长的结点优先级高
            if (f == a.f) return g>a.g;
            return f>a.f;
        }
    };
    
    void add_edge(int u, int v, int w) {
        edge tmp;
        tmp.v = u; tmp.w = w; a[v].push_back(tmp);
        tmp.v = v; tmp.w = w; b[u].push_back(tmp);
    }
    
    void spfa(int s) {
        queue<int>q;
        q.push(s);
        dis[s] = 0; flag[s] = true;
        while (!q.empty()) {
            int u = q.front(); q.pop(); flag[u] = false;
            for (int i = 0; i < a[u].size(); i++) {//扫描所有邻接点
                if (dis[a[u][i].v] > dis[u] + a[u][i].w) {
                    dis[a[u][i].v] = dis[u] + a[u][i].w;
                    if (!flag[a[u][i].v]) {
                        q.push(a[u][i].v);
                        flag[a[u][i].v] = true;
                    }
                }
            }
        }
    }
    
    void Astar(int s, int t) {
        if (s == t)k++;//没有这句会T
        if (dis[s] == inf){ printf("-1
    "); return; }//没有这句会T
        priority_queue<node>q;
        q.push(node(s, 0, 0));
        int cnt = 0;
        while (!q.empty()) {
            node h = q.top(); q.pop();
            if (h.id == t) {
                if (++cnt == k) {
                    printf("%d", h.f);//返回第k短路
                    return;
                }
            }
            for (int i = 0; i < b[h.id].size(); i++) {
                q.push(node(b[h.id][i].v, h.g + b[h.id][i].w + dis[b[h.id][i].v], h.g + b[h.id][i].w));
            }
        }
        printf("-1
    "); return;
    }
    
    int main() {
        a.resize(maxn);
        b.resize(maxn);
        scanf("%d%d%d", &n, &m, &k);
        scanf("%d%d", &s, &t);
        int u, v, w;
        for (int i = 0; i < m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            add_edge(u, v, w);
        }
        spfa(t);
        Astar(s, t);
        return 0;
    }
    
  • 相关阅读:
    用户场景描述
    构建之法阅读笔记03
    冲刺记录(4.26)
    力扣-dp基础问题思维构建
    力扣-二叉树专题
    力扣-巧妙哈希
    力扣-双指针问题
    力扣-区间问题
    力扣-单调栈与单调队列问题
    力扣-股票买卖专题
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489817.html
Copyright © 2011-2022 走看看