bzoj 2763 飞行路线(分层图最短路)

这篇博客介绍了如何解决一道关于飞行路线的最短路径问题,考虑了航空公司的免费航线优惠政策。题目中给出了城市数量、航线信息以及免费乘坐次数,求解从起点到终点的最低费用。博主探讨了使用SPFA算法和Dijkstra算法的差异,并分享了代码实现,指出在处理负数下标时要注意避免WA。
摘要由CSDN通过智能技术生成

*PS:为什么这个题好像卡SPFA,评测里dij跑的要比SPFA快很多ψ(。。) (另:orz…同样打的是SPFA,就我T了。。。QAQ) ,并且数组访问了负数下标竟然显示wa

go to the problem

Description

Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

Input

数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t< n)
接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b< n,a与b不相等,0<=c<=1000)

Output

只有一行,包含一个整数,为最少花费。

Sample Input

5 6 1

0 4

0 1 5

1 2 5

2 3 5

3 4 5

2 3 3

0 2 100

Sample Output

8

HINT

对于30%的数据,2<=n<=50,1<=m<=300,k=0;

对于50%的数据,2<=n<=600,1<=m<=6000,0<=k<=1;

对于100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10.

dalao们都说这是分层图。。。蒟蒻表示不懂。。。
反正de和队列都要开两维记录一下带k的状态就对了。。。我的k是从K~0做的,还要判负数(麻烦QWQ)。。。加了个小优化,跑到了1500+ms。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;

int N,M,K,S,T,A,B,C,cnt;
int first[10010],next[100010];
int de[10010][11],used[10010][11];
struct maple{
    int f,t,d;
}Rode[100010];
struct edge{
    int f,k;
};
queue<edge>q;

void Build(int f,int t,int d)
{
    Rode[++cnt]=(maple){f,t,d};
    next[cnt]=first[f];
    first[f]=cnt;
}
void SPFA()
{
    memset(de,63,sizeof(de));
    used[S][K]=1;
    de[S][K]=0;
    q.push((edge){S,K});
    while(!q.empty())
    {
        edge a=q.front();
        q.pop();
        used[a.f][a.k]=0;
        for(int i=first[a.f];i;i=next[i])
        {
            if(a.k>=1&&de[Rode[i].t][a.k-1]>de[a.f][a.k]) // 这条航线免费 
            {
                de[Rode[i].t][a.k-1]=de[a.f][a.k];
                if(!used[Rode[i].t][a.k-1]&&de[Rode[i].t][a.k-1]<de[T][0])
                {
                    used[Rode[i].t][a.k-1]=1;
                    q.push((edge){Rode[i].t,a.k-1}); 
                }
            }
            if(de[Rode[i].t][a.k]>de[a.f][a.k]+Rode[i].d) // 这条航线不免费 
            {
                de[Rode[i].t][a.k]=de[a.f][a.k]+Rode[i].d;
                if(!used[Rode[i].t][a.k]&&de[Rode[i].t][a.k]<de[T][0])
                {
                    used[Rode[i].t][a.k]=1;
                    q.push((edge){Rode[i].t,a.k}); 
                }
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d",&N,&M,&K,&S,&T);
    for(int i=1;i<=M;++i)
    {
        scanf("%d%d%d",&A,&B,&C);
        Build(A,B,C);
        Build(B,A,C);
    }
    SPFA();
    printf("%d",de[T][0]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值