返回顶部

P4568 [JLOI2011] 飞行路线

原题传送锚点

题目描述

Alice 和 Bob 现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在 n 个城市设有业务,设这些城市分别标记为 0 到 n1,一共有 m 种航线,每种航线连接两个城市,并且航线有一定的价格。

Alice 和 Bob 现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多 k 种航线上搭乘飞机。那么 Alice 和 Bob 这次出行最少花费多少?

输入格式

第一行三个整数 n,m,k,分别表示城市数,航线数和免费乘坐次数。

接下来一行两个整数 s,t,分别表示他们出行的起点城市编号和终点城市编号。

接下来 mm 行,每行三个整数 a,b,c,表示存在一种航线,能从城市 a 到达城市 b,或从城市 b 到达城市 a,价格为 c。

输出格式

输出一行一个整数,为最少花费。

输入输出样例

输入 #1
5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100
输出 #1
8

说明/提示

数据规模与约定

对于 30% 的数据,2n50,1m300,k=0。

对于 50% 的数据,2n600,1m6×1030k1。

对于 100% 的数据,2n1041m5×1040k10,0s,t,a,bn,a≠b,0c103

另外存在一组 hack 数据。

 

 

浅看一下题,发现那个k是真的很烦。

没有k的话不就是标准的最短路吗?

带着略有无奈的心情继续往下翻……!!!什么!!!k∈[0,10]!!!

这是一个关键啊,没想到k竟然这么小。

要不,分十种情况讨论?算了吧,代码这不写死人吗。

继续思考…………!免费的路线,不就是边权为0吗?

k挺小的,那么就可以考虑建分层图了。

把图分为两层,各层内部正常连边,各层之间对应点从上到下连权值为0的边。每向下跑一层,就相当于免费搭一次飞机。跑一遍从s到 t+n∗k的最短路即可。

下图是样例数据间的分层图:

于是乎,这道题就被愉快地解决了。

等等:既然要建分层图,数组一定要开大点啊!!!

const int N=1e7+5;     完全没问题。

Code:

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5;
int n,m,k,s,t,tot;
int d[N],fi[N],ne[N*2],to[N*2],w[N*2];
bool vis[N];
priority_queue<pair<int,int> > q;

void add(int x,int y,int z)
{
    ne[++tot]=fi[x];
    fi[x]=tot;
    to[tot]=y;
    w[tot]=z;
}

void dfs()
{
    memset(d,0x7f,sizeof(d));
    d[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty())
    {
        int x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=fi[x];i;i=ne[i])
        {
            int v=to[i];
            if(d[v]>d[x]+w[i])
            {
                d[v]=d[x]+w[i];
                q.push(make_pair(-d[v],v));
            }
        }
    }
}

int main()
{
    cin>>n>>m>>k>>s>>t;
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        add(x,y,z),add(y,x,z);
        for(int j=1;j<=k;j++)
        {
            add(x+(j-1)*n,y+j*n,0);
            add(y+(j-1)*n,x+j*n,0);
            add(x+j*n,y+j*n,z);
            add(y+j*n,x+j*n,z);
        }
    }
    for(int i=1;i<=k;i++)
        add(t+(i-1)*n,t+i*n,0);
    dfs();
    cout<<d[t+k*n]<<'\n';
}
复制代码


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   光暗之影x  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示