分层图最短路讲解+例题洛谷P4568[JLOI2011]飞行路线

淺唱寂寞╮ 提交于 2019-12-03 05:00:08

分层图最短路。。。听起来有点高大上,其实就只是相当于三维的最短路而已,和三维迷宫一样,我们用dis[i][k]表示起点S到第k层i的最短路,其中同层的图如果是无向图,继续保持,然后用一条由该层指向上一层的有向线段并且费用为0,作为该层到上一层的道路,实际上就是这样的:

由该层向上一层改点的相邻点建边,建完之后就可以直接开始跑最短路了,当然,有2种跑法,(一)可以将k层的点全部列出来,也就是总共k*n个点,然后建很多的边,最后跑最短路,结果访答案的时候:

 

for (int i=0; i<=k; i++)
        ans=min(ans,dis[t+i*n]);

 

(二)普通建边,在跑最短路的队列里面进行操作,这个就比较方便,下面给出代码:

void dij(int st,int ed,int k,int n)
{
    priority_queue<node>q;
    q.push(node{st,0,0});
    dis[st][0]=0;
    while (!q.empty()){
        node now=q.top();
        q.pop();
        int id=now.id%n,fl=now.floor;
        if (vis[id][fl]) continue;
        vis[id][fl]=1;
        for (int i=head[id]; i!=-1; i=eg[i].next){//同层最短路
            int v=eg[i].to;
            if (!vis[v][fl] && dis[v][fl]>dis[id][fl]+eg[i].w){
                dis[v][fl]=dis[id][fl]+eg[i].w;
                q.push(node{v+n*fl,dis[v][fl],fl});
            }
        }
        if (fl<k){
            for (int i=head[id]; i!=-1; i=eg[i].next){//i层到i+1层最短路
                int v=eg[i].to;
                if (!vis[v][fl+1] && dis[v][fl+1]>dis[id][fl]){
                    dis[v][fl+1]=dis[id][fl];
                    q.push(node{v+n*(fl+1),dis[v][fl+1],fl+1});
                }
            }
        }
    }
}

 

理解了这个核心代码之后那么也就不难写出分层图最短路的代码了,下面给出“洛谷P4568[JLOI2011]飞行路线”的题面和AC代码:

题目描述

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。

输出格式

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

输入输出样例

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

说明/提示

对于30%的数据,2n50,1m300,k=0;
对于50%的数据,2n600,1m6000,0k1;
对于100%的数据,2n10000,1m50000,0k10,0s,t<n,0a,b<n,ab,0c1000

 

 以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=5e4+10;
const int inf=5e8+10;

struct Edge
{
    int to,w,next;   
}eg[mac<<1];
struct node
{
    int id,d,floor;
    bool operator <(const node &a)const{
        return d>a.d;
    }
};
int head[mac],num=0,vis[mac][15],dis[mac][15];

void add(int u,int v,int w)
{
    eg[++num]=Edge{v,w,head[u]};
    head[u]=num;
}

void dij(int st,int ed,int k,int n)
{
    priority_queue<node>q;
    q.push(node{st,0,0});
    dis[st][0]=0;
    while (!q.empty()){
        node now=q.top();
        q.pop();
        int id=now.id%n,fl=now.floor;
        if (vis[id][fl]) continue;
        vis[id][fl]=1;
        for (int i=head[id]; i!=-1; i=eg[i].next){
            int v=eg[i].to;
            if (!vis[v][fl] && dis[v][fl]>dis[id][fl]+eg[i].w){
                dis[v][fl]=dis[id][fl]+eg[i].w;
                q.push(node{v+n*fl,dis[v][fl],fl});
            }
        }
        if (fl<k){
            for (int i=head[id]; i!=-1; i=eg[i].next){
                int v=eg[i].to;
                if (!vis[v][fl+1] && dis[v][fl+1]>dis[id][fl]){
                    dis[v][fl+1]=dis[id][fl];
                    q.push(node{v+n*(fl+1),dis[v][fl+1],fl+1});
                }
            }
        }
    }
}

int main()
{
    int n,m,k,st,ed;
    scanf ("%d%d%d",&n,&m,&k);
    scanf ("%d%d",&st,&ed);
    memset(head,-1,sizeof head);
    for (int i=1; i<=m; i++){
        int u,v,w;
        scanf ("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    for (int i=0; i<n; i++)
        for (int j=0; j<=k; j++)
            dis[i][j]=inf;
    dij(st,ed,k,n);
    int ans=inf;
    for (int i=0; i<=k; i++)
        ans=min(ans,dis[ed][i]);
    printf ("%d\n",ans);
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!