• POJ2449 【第k短路/A*】


    题目链接:http://poj.org/problem?id=2449

    题目大意:

    给出n个点,m条有向边,最后一行给出起点到终点的第k短路。求长度。

    题解思路:

    这是我第一道第k短路题以及A*算法的使用。

    这是一篇A*算法讲的非常好的博客:https://blog.csdn.net/weixin_44489823/article/details/89382502

    将A*运用到求第k短路上实际上与文章中的A*是有所不同的。但是精髓没有改变,精髓是寻路时,选择 f 值最小的点,用来避免寻找无用的路径。在A*算法中本应该对所经过的点进行标记,就像是bfs时对已经经过的点进行标记,但在第k短路中不可以,因为需要重复走各个需要走的点。那么在每次走到终点一定是当前一次的最短路,在下一次再次走到终点时,就是第2次最短路,以此类推,第k短路就是第k次到达终点时所走的总路程。

    对于h评估函数,在第k短路是终点到各个点的距离,对原图建一个反向图,以终点为起边来跑一遍最短路即可得到h数组。

    对于g函数,是所走过的距离,即原图起点到该点的距离。

    代码如下:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<queue>
      4 #include<algorithm>
      5 #define mem(a, b) memset(a, b, sizeof(a))
      6 using namespace std;
      7 typedef long long ll;
      8 const int MAXN = 1e3 + 100;
      9 const int MAXM = 1e5 + 100;
     10 const int inf = 0x3f3f3f3f;
     11 
     12 int n, m;    //n个点 m条有向边 
     13 int head[MAXN], cnt, r_head[MAXN], r_cnt;
     14 int vis[MAXN];
     15 ll h[MAXN]; 
     16 
     17 struct Edge
     18 {
     19     int to, next, w;
     20 }e[MAXM], r_e[MAXM];
     21 
     22 struct Node
     23 {
     24     int pot;
     25     ll g, h;
     26     bool operator < (const Node &a)const //优先选择f值小的点 A*算法精髓所在 
     27     {
     28         return g + h > a.g + a.h;
     29     }
     30 }node;
     31 
     32 void add(int a, int b, int c)
     33 {
     34     cnt ++;
     35     e[cnt].to = b;
     36     e[cnt].next = head[a];
     37     e[cnt].w = c;
     38     head[a] = cnt;
     39 }
     40 
     41 void r_add(int a, int b, int c) //反向边 与正向边的编号一致 
     42 {
     43     r_cnt ++;   
     44     r_e[r_cnt].to = b;
     45     r_e[r_cnt].next = r_head[a];
     46     r_e[r_cnt].w = c;
     47     r_head[a] = r_cnt;
     48 }
     49 
     50 int spfa(int st, int ed)  //反向图 跑 h 评估函数(在这里也就是终点到该点的最短距离) A*算法精髓
     51 {
     52     mem(h, inf), mem(vis, 0);
     53     queue<int> Q;
     54     while(!Q.empty())    Q.pop();
     55     vis[st] = 1;
     56     h[st] = 0;
     57     Q.push(st);
     58     while(!Q.empty())
     59     {
     60         int a = Q.front();
     61         Q.pop();
     62         vis[a] = 0;
     63         for(int i = r_head[a]; i != -1; i = r_e[i].next)
     64         {
     65             int to = r_e[i].to;
     66             if(h[to] > h[a] + r_e[i].w * 1ll)
     67             {
     68                 h[to] = h[a] + r_e[i].w * 1ll;
     69                 if(!vis[to])
     70                 {
     71                     vis[to] = 1;
     72                     Q.push(to);
     73                 }
     74             }
     75         }
     76     }
     77     return h[ed] != inf;
     78 }
     79 
     80 ll A_star(int st, int ed, int k) //优先队列 优先选择f值小的点 跑正向图 
     81 {
     82     int num = 0;
     83     priority_queue<Node> QQ;
     84     while(!QQ.empty())    QQ.pop();
     85     node.pot = st, node.g = 0, node.h = h[st];
     86     QQ.push(node);
     87     while(!QQ.empty())
     88     {
     89         Node a = QQ.top();
     90         QQ.pop();
     91 //        printf("%d
    ", a.pot);
     92         if(a.pot == ed)  //如果第k次找到终点 就得出了答案 
     93         {
     94             num ++;
     95             if(num == k)
     96                 return a.g + a.h;
     97         }
     98         for(int i = head[a.pot]; i != -1; i = e[i].next)
     99         {
    100             int to = e[i].to;
    101             node.pot = to;
    102             node.g = a.g + e[i].w * 1ll;
    103             node.h = h[to];
    104             QQ.push(node);
    105         }
    106     }
    107     return -1;
    108 }
    109 
    110 int main()
    111 {
    112     scanf("%d%d", &n, &m);
    113     mem(head, -1), cnt = 0;
    114     mem(r_head, -1), r_cnt = 0;
    115     for(int i = 1; i <= m; i ++)
    116     {
    117         int a, b, c;
    118         scanf("%d%d%d", &a, &b, &c);
    119         add(a, b, c);
    120         r_add(b, a, c);
    121     }
    122     int a, b, k; //a 到 b 的第 k 短路 
    123     scanf("%d%d%d", &a, &b, &k);
    124     if(a == b)
    125         k ++;
    126     if(!spfa(b, a)) 
    127         printf("-1
    "); //若起点到终点本身就不连通 就不存在第k短路 输出-1 
    128     else
    129         printf("%lld
    ", A_star(a, b, k));
    130     return 0;
    131 }
    第k短路模板
  • 相关阅读:
    poj 2104(线段树)
    poj 1962(并查集+带权更新)
    hdu 2818(并查集,带权更新)
    hdu 1856
    hdu 3172
    hdu 1325(并查集)
    hdu 5023
    pku 2777(经典线段树染色问题)
    hdu 1671(字典树判断前缀)
    hdu 1247 (字典树入门)
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/11844528.html
Copyright © 2020-2023  润新知