POJ 2449 Remmarguts' Date——A*

解题思路

本题的题目题目要求就是求给定图的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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值