POJ 2449(A*算法)

题目链接:http://poj.org/problem?id=2449

 

题目大意:求出s到t的第k短路大小

 

题目思路:如果单用优先队列,那就是从s开始疯狂试探,然后一直到取t第k次的时候就是答案。但是很明显有个缺点,就是他需要走很多无谓的路。所以我们需要用到A*算法。A*算法就是多了个估值函数。这里用的是该点到t的最短路值作为估值。这样的话,就可以少走很多路,因为知道后来的情况,所以优先队列开头的都是比之前瞎走更加逼近正确答案的点,也就会更快可以将t取出k次。这里最短路可以通过建反图获得t到各点的最短路也就变成了各点到t的最短路。有两个注意点,一个是如果s到t的距离是无限大,那么就不用继续直接输出-1,还有一个是如果s=t那么需要k++,因为自己到自己距离是0,按照题意不能算第一短的路。

 

以下是代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
#define MAXN 100005
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
int tot,head[MAXN],rhead[MAXN],x,y,z,cnt[MAXN],dist[MAXN];
bool vis[MAXN];
struct Edge{
    int to,next,w;
}edge[MAXN],redge[MAXN];
void addegde(int u,int v,int w){
    edge[tot].to=v;edge[tot].w=w;edge[tot].next=head[u];head[u]=tot;
    redge[tot].to=u;redge[tot].w=w;redge[tot].next=rhead[v];rhead[v]=tot++;
}
struct node{
    friend bool operator<(node n1,node n2){
        return n1.dist>n2.dist;
    }
    int x,dist;
};
priority_queue<node>q;
queue<int>que;
bool spfa(int s,int n){
    memset(vis,false,sizeof(vis));
    rep(i,1,n)dist[i]=inf;
    vis[s]=true;
    dist[s]=0;
    while(!que.empty())que.pop();
    que.push(s);
    memset(cnt,0,sizeof(cnt));
    cnt[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vis[u]=false;
        for(int i=rhead[u];i!=-1;i=redge[i].next){
            int v=redge[i].to;
            if(dist[v]>dist[u]+redge[i].w){
                dist[v]=dist[u]+redge[i].w;
                if(!vis[v]){
                    vis[v]=true;
                    que.push(v);
                    if(++cnt[v]>n)return false;
                }
            }
        }
    }
    return true;
}
int main(){
    int n,m,s,t,k;
    while(~scanf("%d%d",&n,&m)){
        tot=0;
        memset(head,-1,sizeof(head));
        memset(rhead,-1,sizeof(rhead));
        while(m--){
            scanf("%d%d%d",&x,&y,&z);
            addegde(x,y,z);
        }
        scanf("%d%d%d",&s,&t,&k);
        spfa(t,n);
        if(dist[s]==inf){
            printf("-1\n");
            continue;
        }
        while(!q.empty())q.pop();
        node a;
        a.x=s,a.dist=dist[s];q.push(a);
        int ans=-1,num=0;
        if(s==t)k++;
        while(!q.empty()){
            node temp=q.top(),jiang;
            q.pop();
            if(temp.x==t){
                num++;
                if(num==k){
                    ans=temp.dist;
                    break;
                }
            }
            for(int i=head[temp.x];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                jiang.x=v,jiang.dist=temp.dist-dist[temp.x]+dist[v]+edge[i].w;
                q.push(jiang);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值