zoukankan      html  css  js  c++  java
  • 洛谷P4568《飞行路线》

    原更新日期:2018-11-25 09:23:13

    入门级别的分层图最短路

    题目地址
    双倍经验

    前言

    先介绍一下分层图最短路。

    分层图最短路是指在可以进行分层图的图上解决最短路问题。
    一般模型是:
    在图上,有k次机会可以直接通过一条边,问起点与终点之间的最短路径。

    题目描述

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

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

    输入输出格式

    输入格式

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

    第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。

    接下来有m行,每行三个整数,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
    

    解题思路

    这就是分层图最短路的模板
    但为什么是省选/NOI-

    我们用DP的思想来看
    dis[i][j]表示起点到i点在j层的最短路

    如何分层?
    理解性记忆。
    例如本题最多有十层,第k层表示免费了k次的最短路

    如何跑最短路?
    洛谷卡SPFA,BZOJ不卡SPFA,但是都要注意把空间开大10倍,不然是过不去的(5次TLE的惨痛经验)
    在跑 Dijkstra 的时候,我们用了一个pair来存当前到达的点和已走过的路径;这次我们需要多维护一个东西:当前的层数。

    struct Node {
    	int id; // 当前到达的点
    	int weight; // 已走过的路径
    	int now; // 当前的层数
    	
    	Node() {
    		id = weight = now = 0;
    	}
    	
    	// 重载运算符,用于优先队列
    	bool operator < (const Node &that) const {
    		return weight > that.weight;
    	}
    };
    

    在更新dis的时候,我们需要对这一层的点和下一层的点分别进行更新

    if (!vis[to][Floor] && dis[to][Floor] > dis[now][Floor] + edge[e].weight) {
        dis[to][Floor] = dis[now][Floor] + edge[e].weight;
        q.push(NewNode(to, dis[to][Floor], Floor));
    }
    
    if (!vis[to][Floor] && Floor + 1 <= K && dis[to][Floor + 1] > dis[now][Floor]) {
        dis[to][Floor + 1] = dis[now][Floor];
        q.push(NewNode(to, dis[to][Floor + 1], Floor + 1));
    }
    

    代码实现

    /* -- Basic Headers -- */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <queue>
    
    /* -- Defined Functions -- */
    #define For(a,x,y) for (int a = x; a <= y; ++a)
    #define Forw(a,x,y) for (int a = x; a < y; ++a)
    #define Bak(a,y,x) for (int a = y; a >= x; --a)
    
    namespace FastIO {
        inline int getint() {
            int s = 0, x = 1;
            char ch = getchar();
            while (!isdigit(ch)) {
                if (ch == '-') x = -1;
                ch = getchar();
            }
            while (isdigit(ch)) {
                s = s * 10 + ch - '0';
                ch = getchar();
            }
            return s * x;
        }
        inline void __basic_putint(int x) {
            if (x < 0) {
                x = -x;
                putchar('-');
            }
            if (x >= 10) __basic_putint(x / 10);
            putchar(x % 10 + '0');
        }
        
        inline void putint(int x, char external) {
            __basic_putint(x);
            putchar(external);
        }
    }
    
    
    namespace Solution {
        const int MAXN = 100000 + 10;
        const int MAXM = 500000 + 10;
        const int MAXK = 10 + 5;
        
        struct Node {
            int id, weight, now;
            Node() {
                id = weight = now = 0;
            }
            bool operator < (const Node &that) const {
                return weight > that.weight;
            }
        } head[MAXN];
        
        struct Edge {
            int now, next, weight;
        } edge[MAXM];
        
        int n, m, k, s, t, K, cnt, dis[MAXN][MAXK];
        bool vis[MAXN][MAXK];
        
        inline void addEdge(int prev, int next, int weight) {
            edge[++cnt].now = next;
            edge[cnt].weight = weight;
            edge[cnt].next = head[prev].id;
            head[prev].id = cnt;
        }
        
        Node NewNode(int id, int weight, int now) {
            Node tmp;
            tmp.id = id;
            tmp.weight = weight;
            tmp.now = now;
            return tmp;
        }
        
        void SPFA() {
            memset(dis, 0x7f, sizeof(dis));
            std::priority_queue<Node> q;
            For (i, 0, K) dis[s][i] = 0;
            q.push(NewNode(s, 0, 0));
            while (!q.empty()) {
                Node NowNode = q.top();
                q.pop();
                int Floor = NowNode.now;
                int now = NowNode.id;
                if (vis[now][Floor]) continue;
                vis[now][Floor] = true;
                for (int e = head[now].id; e; e = edge[e].next) {
                    int to = edge[e].now;
                    if (!vis[to][Floor] && dis[to][Floor] > dis[now][Floor] + edge[e].weight) {
                        dis[to][Floor] = dis[now][Floor] + edge[e].weight;
                        q.push(NewNode(to, dis[to][Floor], Floor));
                    }
                    if (!vis[to][Floor] && Floor + 1 <= K && dis[to][Floor + 1] > dis[now][Floor]) {
                        dis[to][Floor + 1] = dis[now][Floor];
                        q.push(NewNode(to, dis[to][Floor + 1], Floor + 1));
                    }
                }
            }
        }
    }
    
    signed main() {
        using namespace Solution;
        using FastIO::getint;
        n = getint();
        m = getint();
        k = getint();
        s = getint();
        t = getint();
        K = k;
        For (i, 1, m) {
            int prev = getint();
            int next = getint();
            int weight = getint();
            addEdge(prev, next, weight);
            addEdge(next, prev, weight);
        }
        SPFA();
        int ans = 2147482333;
        for (int i = 0; i <= k; ++i) {
            ans = std::min(ans, dis[t][i]);
        }
        FastIO::putint(ans, '
    ');
        return 0;
    }
    
    
  • 相关阅读:
    codevs 2632 非常好友
    codevs 1213 解的个数
    codevs 2751 军训分批
    codevs 1519 过路费
    codevs 1503 愚蠢的宠物
    codevs 2639 约会计划
    codevs 3369 膜拜
    codevs 3135 River Hopscotch
    数论模板
    JXOJ 9.7 NOIP 放松模拟赛 总结
  • 原文地址:https://www.cnblogs.com/handwer/p/13816444.html
Copyright © 2011-2022 走看看