poj2449--A*算法求解k短路

今天想到了以前早就遗留下来的一个算法–A*算法,基本上,我对于A*只有过简单的了解,却从来没有具体的写过 A*,于是就有了今天的A*学习。

A*算法相比与其他的搜索来说,它多了一个估价函数而已。而估价函数在不同的题目中形式又不同,这正是A*难的地方啊~

对于此题:给出n个点,m条边,可能又重边,给定起点,终点,求k短路。

k短路是A*的一个最简单的应用。
我们可以设计这样的估价函数:
f(u)=g(u)+h(u).f来代表从s到t的总代价,g为s到u的总代价,h是剩下路径的总代价。于是我们可以从t跑一遍spfa,来求解出t到每个点的距离,然后将其加入优先队列中,我们可以知道,k短路即优先队列中第k个到达t的路径。
注意:估价函数的估计代价一定比实际代价少,这样才能是A*满足条件。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define Set(aa,bb) memset(aa,bb,sizeof(aa))
using namespace std;
const int maxn=100010,maxm=1010,inf=0x3f3f3f3f;
int be[maxn],ne[maxn],to[maxn],w[maxn],e;
int revbe[maxn],revne[maxn],revto[maxn],revw[maxn],reve;
int dis[maxm];
bool vis[maxn];
int n,m,s,t,k;

struct Astar{
    int f,g,p;//f表示路程和,g表好已经走过的路程,h表示对应的点
    bool operator <(const Astar a)const{
        return f==a.f?g>a.g:f>a.f;
    }
};

void add(int x,int y,int z){
    ne[++e]=be[x],be[x]=e,to[e]=y,w[e]=z;
    revne[e]=revbe[y],revbe[y]=e,revto[e]=x,revw[e]=z;
}

void spfa(int node){
    For(i,1,n) dis[i]=inf,vis[i]=0;
    dis[node]=0;
    int q[maxn],f=0,l=0;
    q[++l]=node;vis[node]=1;
    while(f<l){
        int ls=q[++f];vis[ls]=0;
        for(int i=revbe[ls];i;i=revne[i]){
            int u=revto[i];
            if(dis[u]>dis[ls]+revw[i]){
                dis[u]=dis[ls]+revw[i];
                if(!vis[u]){
                    vis[u]=1;
                    q[++l]=u;
                }
            }
        }
    }
}

int A_star(int l,int r){
    if(dis[l]==inf) return -1;
    if(l==r) ++k;
    priority_queue<Astar>q;
    Astar now;
    now.g=0,now.p=l,now.f=dis[l];
    q.push(now);
    int sum=0;
    while(!q.empty()){
        Astar ls=q.top();q.pop();
        if(ls.p==r){
            ++sum;
            if(sum==k) return ls.g;
        }
        for(int i=be[ls.p];i;i=ne[i]){
            now.p=to[i];
            now.g=ls.g+w[i];
            now.f=now.g+dis[to[i]];
            q.push(now);
        }
    }
    return -1;
}

void work(){
    scanf("%d%d",&n,&m);
    For(i,1,m){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    scanf("%d%d%d",&s,&t,&k);
    spfa(t);
    printf("%d\n",A_star(s,t));
}

int main(){
#ifndef ONLINE_JUDGE 
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    work();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值