【模板】 $\text{K}$ 短路

Tags

搜索、\(\text{A*}\)很酷很炫的算法


  • 定义二元组\(\text{DIS(X,Now)}\)表示到达\(\text{X}\)点,路程是\(\text{Now}\)
  • 反向\(\text{SPFA/Dijkstra}\)作为每个点的估价函数;
  • 从队首取出\(\text{DIS}\),扩展状态;
  • 每当获得一个\(\text{DIS}​\)就加入到\(\text{priority_queue}​\)里面去;

Code:

#include <cstdio>
#include <cstring>
#include <queue>
#define re register
#define GC getchar()
#define Clean(X,K) memset(X,K,sizeof(X))
int Qread () {
    int X = 0 ; char C = GC ;
    while (C > '9' || C < '0') C = GC ;
    while (C >='0' && C <='9') {
        X = X * 10 + C - '0' ;
        C = GC ;
    }
    return X ;
}
const int Maxn = 5005 , Maxm = 400005 , INF = 20021020 << 2;
int N , M , Head[Maxn] , En = 0 , Vis[Maxn] ;
double Ek , Mdis[Maxn];
struct DIS {
    int X ;
    double Now ;
};
bool operator < (const DIS &A , const DIS &B) {
    return A.Now + Mdis[A.X ] > B.Now + Mdis[B.X ] ;
}
std :: priority_queue <DIS> Q ;
struct Edge {
    int From_Point , Goto_Point , Next_Edge ;
    double Lenth_of_Edge ;
};
Edge E[Maxm] ;
void Adg (int X , int Y , double L) {
    E[++En].From_Point =X ;
    E[En].Goto_Point = Y ;
    E[En].Next_Edge = Head[X] ;
    E[En].Lenth_of_Edge = L ;
    Head[X] = En ;
}
void SPFA () {
    std :: queue <int> Q ;
    for (re int i = 1 ; i <= N; ++ i) Mdis[i] = INF ;
    Clean (Vis , 0) , Mdis[N] = 0 ;
    Q.push(N) ;
    while (!Q.empty()) {
        int Now = Q.front() ;
        Q.pop() ;
        Vis[Now] = 0 ;
        for (re int i = Head[Now] ; i; i = E[i].Next_Edge ) {
            double Dis = Mdis[Now] + E[i].Lenth_of_Edge ;
            if (Mdis[E[i].Goto_Point ] > Dis) {
                Mdis[E[i].Goto_Point ] = Dis ;
                if (!Vis[E[i].Goto_Point ]) {
                    Vis[E[i].Goto_Point ] = 1 ;
                    Q.push(E[i].Goto_Point ) ;
                }
            }
        }
    }
}
DIS Mp (int X , double Now) {
    DIS Ans ;
    Ans.X = X , Ans.Now = Now ;
    return Ans ;
}
int main () {
//  freopen ("P2483.in" , "r" , stdin) ;
    N = Qread () , M = Qread () ;
    scanf ("%lf" , &Ek) ;
    Clean (Head , 0) , En = 0 ;
    for (re int i = 1 ; i <= M; ++ i) {
        double L ;
        int X = Qread () , Y = Qread () ;
        scanf ("%lf" , &L) ;
        Adg (Y , X , L) ;
    }
    SPFA () ;
    Clean(Head , 0 ) , En = 0 , M <<= 1 ;
    for (re int i = 1 ; i <= M ; ++ i) Adg (E[i].Goto_Point , E[i].From_Point , E[i].Lenth_of_Edge ) ;
    M >>= 1 ;
    Q.push(Mp(1 , 0)) ;
    int Ans = 0 ;
    while (!Q.empty()) {
        DIS Now = Q.top() ;
        Q.pop() ;
        if (Now.X == N) {
            Ek -= Now.Now ;
            if (Ek < 0) break ;
            ++ Ans ;
            continue ;
        }
        for (re int i = Head[Now.X ] ; i; i = E[i].Next_Edge ) Q.push(Mp(E[i].Goto_Point , Now.Now + E[i].Lenth_of_Edge )) ;
    }
    printf ("%d\n" , Ans) ;
    fclose (stdin) , fclose (stdout) ;
    return 0 ;
}

Thanks!

转载于:https://www.cnblogs.com/bj2002/p/10545822.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值