P4568 [JLOI2011] 飞行路线(分层图最短路模板题)
[JLOI2011] 飞行路线
题目描述
Alice 和 Bob 现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在 \(n\) 个城市设有业务,设这些城市分别标记为 \(0\) 到 \(n-1\),一共有 \(m\) 种航线,每种航线连接两个城市,并且航线有一定的价格。
Alice 和 Bob 现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多 \(k\) 种航线上搭乘飞机。那么 Alice 和 Bob 这次出行最少花费多少?
输入格式
第一行三个整数 \(n,m,k\),分别表示城市数,航线数和免费乘坐次数。
接下来一行两个整数 \(s,t\),分别表示他们出行的起点城市编号和终点城市编号。
接下来 \(m\) 行,每行三个整数 \(a,b,c\),表示存在一种航线,能从城市 \(a\) 到达城市 \(b\),或从城市 \(b\) 到达城市 \(a\),价格为 \(c\)。
输出格式
输出一行一个整数,为最少花费。
样例 #1
样例输入 #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\%\) 的数据,\(2 \le n \le 50\),\(1 \le m \le 300\),\(k=0\)。
对于 \(50\%\) 的数据,\(2 \le n \le 600\),\(1 \le m \le 6\times10^3\),\(0 \le k \le 1\)。
对于 \(100\%\) 的数据,\(2 \le n \le 10^4\),\(1 \le m \le 5\times 10^4\),\(0 \le k \le 10\),\(0\le s,t,a,b\le n\),\(a\ne b\),\(0\le c\le 10^3\)。
另外存在一组 hack 数据。
// Problem: P4568 [JLOI2011] 飞行路线 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P4568 // Memory Limit: 125 MB // Time Limit: 1000 ms // Created Time: 2022-07-13 21:04:07 // // Powered by CP Editor (https://cpeditor.org) //fw #include<bits/stdc++.h> #define zp ios::sync_with_stdio(false);cin.tie(0); cout.tie(0); #define pii pair <int, int> #define pll pair <ll, ll> #define endl '\n' #define il inline #define pb push_back #define fi first #define se second #define lc u<<1 #define rc u<<1|1 using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int N=1e6+10,M=5e6+10; int h[N],e[M],ne[M],w[M],idxn,m,k,idx,S,T,n; bool st[N]; int dist[N]; void add(int a,int b,int c) { e[idx]=b; w[idx]=c; ne[idx]=h[a]; h[a]=idx++; } void dijkstra() { memset(dist,0x3f,sizeof dist); dist[S]=0; priority_queue<pii,vector<pii>,greater<pii>>heap; heap.push({0,S}); while(heap.size()) { auto t=heap.top(); heap.pop(); int ver=t.second,dis=t.first; if(st[ver])continue; st[ver]=true; for(int i=h[ver];~i;i=ne[i]) { int j=e[i]; if(dist[j]>dis+w[i]) { dist[j]=dis+w[i]; heap.push({dist[j],j}); } } } } int main() { zp memset(h,-1,sizeof h); cin>>n>>m>>k>>S>>T; while(m--) { int a,b,c; cin>>a>>b>>c; add(a,b,c);//第一层建图 add(b,a,c); for(int j=1;j<=k;j++) { add(a+(j-1)*n,b+j*n,0);//建立每层图之间的免费边,走该条边进入下一层相当于使用了一次免费机会 add(b+(j-1)*n,a+j*n,0); add(a+j*n,b+j*n,c);//每层图之间建边 add(b+j*n,a+j*n,c); } } dijkstra(); int ans=0x3f3f3f3f; for(int i=0;i<=k;i++)//由于到达终点时k次免费机会可能没用用尽,所以需要扫描一遍,也可以在每层图的终点间建立一条免费边 { ans=min(ans,dist[T+i*n]); } cout<<ans<<endl; return 0; }
2022/8/26 ps: 最近在更网络流24题的博客,做到了P4009 汽车加油行驶问题也是一道可以分层图最短路做的题
本文作者:Avarice_Zhao
本文链接:https://www.cnblogs.com/avarice/p/16475697.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步