POJ 2449 Remmarguts' Date——A*

来源:互联网 发布:淘宝主图片尺寸 编辑:程序博客网 时间:2024/06/15 05:54

解题思路

本题的题目题目要求就是求给定图的K短路。
在此之前,我只可以求解最短路问题,而学了A*之后就可以求解这一类问题。

A*的概念

A*是一种广泛用于寻路的算法。之所以其能运用广泛是因为A*效率极高。主要思想就是通过当前最小成本(最小距离或时间)来解决方案。

A*的实现过程

A*有点类似于spfa,但是A*选择最短的路径是通过函数

f(n)=g(n)+h(n)
,其中g(n)是起点到n的代价,h(n)则是估价函数(估价函数随题目的不同而不同,在网格图中一般使用曼哈顿距离拿来估价,地图中则是直线距离)。并且A*通过优先队列来实行重复的选择最小成本。

K短路的实现

K短路的估价函数就是n到终点的最短路(这个可以提前用spfa预处理处理),显然第K次达到终点就是K短路。

时间复杂度

最坏的时空复杂度都为b^d,但是显然比这个值小,所以效率玄学。

下面这张图有助于理解,估价函数是曼哈顿距离。

#include<cstdio>#include<cstring>#include<queue>using namespace std;const int maxn=1005,maxm=100005;int nxt[maxm][2],son[maxm][2],tot[2],lnk[maxn][2],w[maxm][2];int n,m,s,t,k,num,que[maxn],hed,til,dst[maxn];bool vis[maxn];struct jz{    int x,w;    bool operator<(const jz &b)const{        return w+dst[x]>b.w+dst[b.x];    } };priority_queue<jz> heap;inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}void add(int d,int x,int y,int z){    nxt[++tot[d]][d]=lnk[x][d];lnk[x][d]=tot[d];son[tot[d]][d]=y;w[tot[d]][d]=z;}void spfa(){    memset(dst,63,sizeof(dst));    til=1;que[1]=t;vis[t]=1;dst[t]=0;    while (hed!=til){        hed=(hed+1)%maxn;        int x=que[hed];vis[x]=0;        for (int j=lnk[x][1];j;j=nxt[j][1])        if (dst[x]+w[j][1]<dst[son[j][1]]){            dst[son[j][1]]=dst[x]+w[j][1];            if (!vis[son[j][1]]){                til=(til+1)%maxn;                que[til]=son[j][1];vis[son[j][1]]=1;            }        }    }}void A_star(){    heap.push((jz){s,0});    while (!heap.empty()){        jz x=heap.top();heap.pop();        if (x.x==t&&++num==k){printf("%d\n",x.w);break;}        for (int j=lnk[x.x][0];j;j=nxt[j][0]) heap.push((jz){son[j][0],x.w+w[j][0]});    }}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    n=_read();m=_read();    for (int i=1;i<=m;i++){        int x=_read(),y=_read(),z=_read();        add(0,x,y,z);add(1,y,x,z);    }    s=_read();t=_read();k=_read();    if (s==t) k++;spfa();A_star();    if (num<k) printf("-1\n");    return 0;}