A*与K短路

A*算法

一般的搜索有两种:BFS或DFS。这两种搜索都有一个特点,就是搜索顺序与每个节点与起点的距离有关,但是,这样搜索的节点很多是没有必要的,在现实中,我们在走下一步时,还要考虑下一步到终点的距离, A 算法就是在普通的BFS中加一个估价函数,对下一步到终点的距离进行估计,优先搜索到起点的距离与到终点距离的估价值的和小的节点,设想一下,如果估价函数就是当前点到终点的距离,那么这个搜索每一步走的都是最优解,但是,由于估价函数只是预先估计,一般不可能做到完全等于现实中的距离,但是这样也比直接搜索优秀。一般来说,如果是在矩阵中,那么估价函数可以用曼哈顿距离。由于复杂度完全取决于估价函数的好坏(越接近真实距离越好),所以 A 算法的时间复杂度于空间复杂度都是玄学。

K短路

求最短路很简单,求次短路也很简单(只要把最短路上的某一条边去掉后再重新刷最短路,所有的值中最小的就是次短路),但是要求k短路好像就有点麻烦了。
设想一下,如果A*的估价函数完全与真实距离相等,那么每一次搜索到终点都是当前最优的,所以第k次搜索到终点的距离就是k短路了。估价函数完全可以预处理,只要把所有的边倒过来,然后从终点开始刷最短路,从终点到每个点的距离就是那个点的估价函数。
模板题:POJ 2449
代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 1006
#define maxe 100006
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int n,e,ans,S,T,K,hed,tal,tot[2],que[maxn],dis[maxn],lnk[2][maxn],nxt[2][maxe],son[2][maxe],w[2][maxe];
bool vis[maxn];
struct data{
    int x,g;
    data(int X,int G){x=X,g=G;}
    bool operator <(const data&b)const{
        return g+dis[x]>b.g+dis[b.x];
    }
};
priority_queue<data> heap;
void add(int p,int x,int y,int z){
    nxt[p][++tot[p]]=lnk[p][x];son[p][tot[p]]=y;w[p][tot[p]]=z;lnk[p][x]=tot[p];
}
void spfa(){
    memset(dis,63,sizeof(dis));memset(vis,0,sizeof(vis));
    hed=0;que[tal=1]=T;vis[T]=1;dis[T]=0;
    while(hed!=tal){
        hed=(hed+1)%maxn;vis[que[hed]]=0;
        for(int j=lnk[1][que[hed]];j;j=nxt[1][j]) if(dis[son[1][j]]>dis[que[hed]]+w[1][j]){
            dis[son[1][j]]=dis[que[hed]]+w[1][j];
            if(!vis[son[1][j]]){
                vis[son[1][j]]=1;
                que[tal=(tal+1)%maxn]=son[1][j];
                if(dis[que[tal]]<dis[que[(hed+1)%maxn]])swap(que[tal],que[(hed+1)%maxn]);
            }
        }
    }
}
void A_star(){
    while(!heap.empty())heap.pop();
    heap.push(data(S,0));
    while(!heap.empty()){
        data x=heap.top();heap.pop();
        if(x.x==T&&(!(--K))){
            printf("%d",x.g);
            return;
        }
        for(int j=lnk[0][x.x];j;j=nxt[0][j])heap.push(data(son[0][j],x.g+w[0][j]));
    }
}
int main(){
    freopen("dist.in","r",stdin);
    freopen("dist.out","w",stdout);
    n=_read();e=_read();
    for(int i=1,x,y,z;i<=e;i++)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(K)printf("-1");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值