Remmarguts' Date POJ - 2449 第k短路 SPFA+A*

19 篇文章 0 订阅
19 篇文章 0 订阅

这是一道巧妙利用了A*算法的一道题

A*算法比较开心的地方是在算出最短路的时候,继续算下去会得到次最短路,继续下去是次次最短路,….所有可能的路.

在A*算法中 F(x)=G(x)+H(x)
其中G(x) 表示到x后已经走了的距离
H(x) 表示到x后再到终点估计要走多少(本题可以精确算出用SPFA)
F(x) 即是走这条路到达的期望距离

一个比较给力的剪枝 每个点访问k次就好了,多余的并没有对答案有任何的贡献
代码如下:

/*
 * Author       :  Echo
 * Email        :  1666424499@qq.com  
 * Description  :   
 * Created Time :  2017/10/5 10:36:41
 * Last Modify  :  2017/10/5 20:26:55
 * File Name    :  k_thRoad.cpp
 */
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <time.h>
#define LL long long
#define mem(a,k) memset(a,k,sizeof(a))
using namespace std;
const int maxint = -1u>>1;
const int maxn=1e3+10;
const int maxm=1e6+100;
int H[maxn],vis[maxn];
int cnt[maxn];
struct node{
    int f,g,s;
    friend bool operator<(node a,node b){
        return a.f>b.f;
    }
};
struct edge{
    int to,value,next;
    void set(int a,int b,int c){
        to=a,value=b,next=c;
    }
}an[maxm],bn[maxm];
int heada[maxn],cnta,headb[maxn],cntb;
int n,m;
int s,t,k;
void addedge(int u,int v,int value){
    an[cnta].set(v,value,heada[u]);
    heada[u]=cnta++;
    bn[cntb].set(u,value,headb[v]);
    headb[v]=cntb++;
}
void getH(){//spfa
    for(int i=0;i<=n;i++) H[i]=1e9;
    H[t]=0;
    vis[t]=1;
    queue<int> que;
    que.push(t);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vis[u]=0;
        for(int i=headb[u];i!=-1;i=bn[i].next){
            int v=bn[i].to;
            if(H[v]>H[u]+bn[i].value){
                H[v]=H[u]+bn[i].value;
                if(!vis[v])que.push(v),vis[v]=1;
            }
        }
    }
}
int A_star(){
    getH();
    //for(int i=1;i<=n;i++){
        //printf("%d ",H[i]);
    //}
    //cout<<endl;
    priority_queue<node>que;
    node now;
    now.g=0;
    now.s=s;
    now.f=now.g+H[now.s];
    que.push(now);
    while(!que.empty()){
        now=que.top();
        que.pop();
        cnt[now.s]++;
        if(cnt[now.s]>k) continue;
        //printf("test 1:%d %d %d\n",now.s,now.g,now.f);
        node nxt;
        if(now.s==t&&cnt[now.s]==k)return now.f;
        for(int i=heada[now.s];i!=-1;i=an[i].next){
            if(H[an[i].to]==1e9)continue;
            nxt.g=now.g+an[i].value;
            nxt.s=an[i].to;
            nxt.f=nxt.g+H[nxt.s];
            //printf("test 2:%d %d %d\n",nxt.s,nxt.g,nxt.f);
            que.push(nxt);
        }
    }
    return -1;
}
int main(){
    cin>>n>>m;
    memset(heada,-1,sizeof(heada));
    memset(headb,-1,sizeof(headb));
    for(int i=1;i<=m;i++){
        int a,b,v;
        scanf("%d%d%d",&a,&b,&v);
        addedge(a,b,v);
    }
    scanf("%d%d%d",&s,&t,&k);
    if(s==t)k++;
    printf("%d",A_star());
    return 0;
}

/*
7 8
1 2 2
2 4 2
4 5 2
5 7 2
1 3 2
3 2 2
4 6 1
2 1 2
1 1 2

 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值