把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【最短路/Dp】飞行路线(洛谷P4568)

题目描述

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

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

输入

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

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

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

输出

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

Solution:

乍一看不就是多了一个免费功能的最短路,最初的想法应该就是跑一遍最短路贪心把最贵的k条边免费掉,但是这显然可以被证误,很容易就能找出反例。

那么这题运用的是分层图的思路,什么是分层图呢?其实分层图也是一种dp的思想我们可以把原图分为k+1张完全相同的图,也相当于将每个点拆成k+1个点,我们把这k+1张图就看成1楼、2楼、3楼等等这个样子,然后原本有连边的点除了同层的对应点连上对应权值的边,再向下一层对应的点连上一条权值为0的单向边,我们也就可以理解成,每上升一楼,我们就会消耗一次免费机会,然后再在把这k+1层图连接成的大图上跑最短路即可,起点是第一层的起点,终点就是最后一层的终点。值得注意的是,向下一层的连边一定得是单向边,毕竟没有消耗完免费次数还能回来的说法。

另外,luogu在原基础上还增加了一组hack数据为k>m的情况,此时只是按照上面步骤最后会始终跑不到终点,此时只要在每层的终点之间加个权值为0的单向边即可

Code:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct Xhs{
 4     int id,Lenth;
 5     friend bool operator <(Xhs a,Xhs b){
 6         return a.Lenth>b.Lenth;
 7     }
 8 };
 9 priority_queue<Xhs>Q;
10 int Head[5000007];
11 int N,M,K,S,T;
12 const int inf=INT_MAX;
13 int tot,Dis[5000007],vis[5000007];
14 struct Node{
15     int X;
16     int Y;
17     int Val;
18     int Next;
19 }Edge[5000007];
20 void AddEdge(int x,int y,int val)
21 {
22     Edge[++tot].Next=Head[x];
23     Head[x]=tot;
24     Edge[tot].X=x;
25     Edge[tot].Y=y;
26     Edge[tot].Val=val;
27 }
28 int main()
29 {
30     cin>>N>>M>>K;
31     scanf("%d%d",&S,&T);
32     for(int i=1;i<=M;i++){
33         int a,b,c;
34         scanf("%d%d%d",&a,&b,&c);
35         AddEdge(a,b,c);
36         AddEdge(b,a,c);
37         for(int j=1;j<=K;j++){
38             AddEdge(a+N*j,b+N*j,c);
39             AddEdge(b+N*j,a+N*j,c);
40             AddEdge(a+N*(j-1),b+N*j,0);
41             AddEdge(b+N*(j-1),a+N*j,0);
42         }
43     }
44     for(int i=0;i<=N*(K+1);i++)<% Dis[i]=inf;%>
45     for(int i=1;i<=K;i++)
46         AddEdge(T+(i-1)*N,T+i*N,0);
47     Dis[S]=0;
48     Q.push({S,0});
49     while(!Q.empty()){
50         int QAQ=Q.top().Lenth;
51         int TAT=Q.top().id;
52         Q.pop();
53         if(vis[TAT]) continue;
54         vis[TAT]=1;
55         for(int i=Head[TAT];i;i=Edge[i].Next){
56             if(Dis[Edge[i].Y]>Dis[Edge[i].X]+Edge[i].Val){
57                 Dis[Edge[i].Y]=Dis[Edge[i].X]+Edge[i].Val;
58                 if(!vis[Edge[i].Y]) Q.push({Edge[i].Y,Dis[Edge[i].Y]});
59             }
60         } 
61     }
62     cout<<Dis[T+N*K];
63     return 0; 
64 }

 

posted @ 2020-08-07 14:30  fluoce  阅读(157)  评论(0编辑  收藏  举报

Contact with me