zoukankan      html  css  js  c++  java
  • 分层图最短路讲解+例题洛谷P4568[JLOI2011]飞行路线

    分层图最短路。。。听起来有点高大上,其实就只是相当于三维的最短路而已,和三维迷宫一样,我们用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
    ",ans);
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    Go语言基础(四)
    Go语言基础(一)
    Go语言简介和开发环境搭建
    数据分析(四)数据可视化之Matplotlib
    数据分析(三)Pandas
    git简介与基本操作
    drf框架之三大认证之频率类源码分析
    数据分析(二)numpy
    换零钱问题的非递归解法 SICP 1.2.2中的一个问题
    # Java中的代理类
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/11777377.html
Copyright © 2011-2022 走看看