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

现在来了解A*算法是什么

现在来解决A*求K短路问题

 在一个有权图中,从起点到终点最短的路径成为最短路,第2短的路成为次短路,第3短的路成为第3短路,依此类推,第k短的路成为第k短路。那么,第k短路怎么求呢?

  对于第k短路,可以想到的一个比较朴素的算法就是广度优先搜索,使用优先队列从源点s进行广搜,当第k次搜索到终点t时,所的长度即所求但是这种方法在运行过程中会产生特别多的状态,当图比较简单、k比较小时,可以一试,但是当k较大或者图中点数较多时,会面临爆栈的危险。目前使用比较多的算法是单源最短路配合A*。A*是搜索中比较高级的方式,A*算法结合了启发式方法(这种方法通过充分利用图给出的信息来动态的作出决定而使搜索次数大大降低)和形式化方法(这种方法不利用图给出的信息,而仅通过数学的形式分析,如Dijkstra算法)。它通过一个估价函数f(h)来估计图中的当前点p到终点的距离,并由此决定它的搜索方向,当这条路径失败时,它会尝试其他路径。对于A*,估价函数=当前值+当前位置到终点的距离,即f(p)=g(p)+h(p),每次扩展估价函数值最小的一个。对于第k短路算法来说,g(p)为从源点s到当前点p所走的路径长度,h(p)为从当前点p到终点t的最短路,因此f(p)的意义就是从s按照当前路径经过p点后到达t的总距离。也就是每次扩展都是有方向的,这样无论对提高出解的速度还是降低扩展的状态数目都是有好处的。为了加快计算,h(p)需要在搜索之前进行预处理,只要将原图的所有边反向,再从终点t做一次单源最短路即可得到h(p)。单源最短路求法有Dijkstra,Bellman-Ford,SPFA等。

  具体步奏:

  这里我们使用链式前向星来存储如图,由于需要预处理所有点到终点的最短路,就需要将图G中所有边反向得到图G‘,再从终点t做一次单源最短路,所以实际上就是两张图。

  (1)将有向图的所有边反向(无向图可以省略此步),以原图终点t为源点做一次单源最短路,结果记入数组dis[i]中,dis[i]即为原图中点i到点t的最短距离。这里的dis[i]即上述的h(p);

  (2)新建一个优先队列,将源点s加入到队列中;

  (3)从优先队列中弹出f(p)最小的点p(这里如果存在f(p)相等的点,则弹出g(p)最小的点),如果点p就是终点t,则计算t出队列的次数,如果当前为t的第k次出队,则当前路径长度就是s到t的第k短路,算法结束;否则遍历与p相连的所有的边,将扩展出的到p的邻接点信息加入到优先队列。

  值得注意的是,当s==t时需要计算(k+1)短路,因为s到t这条距离为0的路不能算在这k短路中,这时只需将k自增1后再求第k短路即可。

现在来实战下:

题意 : 给出一个有向图、求起点 s 到终点 t 的第 k 短路、不存在则输出 -1

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
const int INF  = 0x3f3f3f3f;
const int maxn = 1024;
const int maxm = 100008;
struct EDGE{ int v, nxt, w; };
struct NODE{
    int pos, Cost, F;
    bool operator < (const NODE & rhs) const {//重载的时候注意符号
        if(this->F == rhs.F) return this->Cost > rhs.Cost;
        return this->F > rhs.F;
    };
};

EDGE Edge[maxm];
EDGE REdge[maxm];
int Head[maxn], RHead[maxn];
int cnt, Rcnt;
int N;
void init()
{
    memset(Head, -1, sizeof(Head));
    memset(RHead, -1, sizeof(RHead));
    cnt = Rcnt = 0;
}

void AddEdge(int from, int to, int weight)
{
    Edge[cnt].w = weight;
    Edge[cnt].v = to;
    Edge[cnt].nxt = Head[from];
    Head[from] = cnt++;
}

void AddREdge(int from, int to, int weight)
{
    REdge[Rcnt].w = weight;
    REdge[Rcnt].v = to;
    REdge[Rcnt].nxt = RHead[from];
    RHead[from] = Rcnt++;
}

int vis[maxn];
int H[maxn];
void SPFA(int st)
{
    queue<int> que;
    memset(H, INF, sizeof(H));
    memset(vis, 0, sizeof(vis));
    H[st] = 0;
    que.push(st);
    while(!que.empty()){
        int cur = que.front(); que.pop();
        vis[cur] = 0;
        for(int i=RHead[cur]; i!=-1; i=REdge[i].nxt) {
            int v = REdge[i].v;
            if(H[v] > H[cur] + REdge[i].w) {
                H[v] = H[cur] + REdge[i].w;
                if(!vis[v]) {
                    vis[v] = 1;
                    que.push(v);
                }
            }
        }
    }
}

int A_Star(int s, int t, int k)
{
    if(s == t) k++;
    if(H[s]==INF) return -1;
    priority_queue<NODE> que;
    NODE cur, into;
    cur.pos = s;
    cur.Cost = 0;
    cur.F = H[s];
    que.push(cur);
    int CNT = 0;
    while(!que.empty()){
        cur = que.top();
        que.pop();
        if(cur.pos == t) CNT++;
        if(CNT == k) return cur.Cost;
        for(int i=Head[cur.pos]; i!=-1; i=Edge[i].nxt){
            into.Cost = cur.Cost+Edge[i].w;
            into.F = cur.Cost+Edge[i].w+H[Edge[i].v];
            into.pos = Edge[i].v;
            que.push(into);
        }
    }return -1;
}

int main(void)
{
    int M, K, S, des;
    while(~scanf("%d %d", &N, &M)){
        init();
        int from, to, weight;
        while(M--){
            scanf("%d %d %d",&from, &to, &weight);
             AddEdge(from, to, weight);
            AddREdge(to, from, weight);//建反向边
        }
        scanf("%d %d %d", &S, &des, &K);
        SPFA(des);//求其他点到终点的最短路,作为H值
        printf("%d\n", A_Star(S,des,K));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/shuaihui520/p/9623597.html

时间: 2024-11-05 14:39:12

A*算法的认识与求第K短路模板的相关文章

poj 2449 Remmarguts&#39; Date 求第k短路 Astar算法

=.=好菜 #include <iostream> #include <cstdio> #include <string.h> #include <cstring> #include <queue> using namespace std; const int N = 1e3+10; const int M = 100000+10; typedef long long ll; const ll INF = 1e15; int n,m,head[N

poj 2449 Remmarguts&#39; Date A*+spfa求第k短路

题意: 经典的第k短路,A*算法的经典应用之一. 分析: A*,已走的路程g+到终点的最短距离为启发函数,搜索过程中不判重,第k次到t节点时就求出了第k短路. 代码: //poj 2449 //sep9 #include <iostream> #include <queue> using namespace std; const int maxN=1024; const int maxM=100024; int n,m,s,t,k,e,ne; int head[maxN],nhea

POJ 2449 求第K短路

第一道第K短路的题目 QAQ 拿裸的DIJKSTRA + 不断扩展的A* 给2000MS过了 题意:大意是 有N个station 要求从s点到t点 的第k短路 (不过我看题意说的好像是从t到s 可能是出题人写错了) 从这题中还真的学到了很多1.第k短路的算法 A* 还有用边表实现dij (注:以下部份资料来源于网上)所谓A*就是启发是搜索 说白了就是给搜索一个顺序使得搜索更加合理减少无谓的搜索. 如何来确定搜索的顺序?..也就是用一个值来表示 这个值为f[n]..每次搜索取f[x]最小的拓展 那

[poj2449]Remmarguts&#39; Date(K短路模板题,A*算法)

解题关键:k短路模板题,A*算法解决. #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N=1e3+10; const

poj 2449 Remmarguts&#39; Date (k短路模板)

Remmarguts' Date http://poj.org/problem?id=2449 Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30772   Accepted: 8397 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly tou

POJ 2449 Remmarguts&#39; Date(k短路模板)

link:https://vjudge.net/problem/POJ-2449 前面输入与大多最短路题相同 最后一行输入s,t,k 求从s到t的第K短路 #include <iostream> #include <cstring> #include <queue> using namespace std; const int MAXN=1010; struct node { int p,g,h; bool operator < (node a) const {

POJ 2449Remmarguts&#39; Date K短路模板 A*+SPFA

太水了我不想说了,模板在这里 14312K 313MS 1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int v[100010],v2[100010],c[100010],c2[100010],s,t,k,duin; 7 int n,m,point[1010],next[100010],cnt=0,

&lt;学习笔记&gt; A*算法求第k短路

一条前往题面的隧道 简洁题面 第一行给出N(点数),M(边数)(1 <= N <= 1000, 0 <= M <= 100000).. 下面的M行每行给出三个数Ai,Bi,Ti,表示从A到B有一条权值为T的单向边. 最后给出S,T,K,表示求S到T的第K短路. special: 起点与终点相同时,S–>S (d=0) 不能算作一条路. 题目会给出多组数据. 即使有好几条路到T的距离都相同,它们仍被记为不同的路. 正解 A*算法 记g[i]为起点s到i的距离,h[i] (期望值

A* 算法求第 K 短路

一种具有 \(f(n)=g(n)+h(n)\) 策略的启发式算法能成为 A* 算法的充分条件是: 搜索树上存在着从起始点到终了点的最优路径. 问题域是有限的. 所有结点的子结点的搜索代价值 \(>0\). \(h(n) \le h^\ast (n)\) (\(h^\ast (n)\) 为实际问题的代价值). Remmarguts' Date 求 S 到 T 的第 K 短路. 思路: (1) 将有向图的所有边反向,以原终点T为源点,求解T到所有点的最短距离. (2) 新建一个优先队列,将源点S加入