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;
    }
    
    
  • 相关阅读:
    SDUTOJ 2775 小P的故事——奇妙的饭卡
    STL vector的构造函数和析构函数(2)
    Spark调研笔记第6篇
    【精】iOS GCD 具体解释
    爆头
    uva 624 CD
    一站式学习Wireshark(转载)
    TCP的状态 (SYN, FIN, ACK, PSH, RST, URG)
    loadrunner两个函数:取参数长度和时间戳函数
    自行控制loadrunner的socket协议性能测试 (转)
  • 原文地址:https://www.cnblogs.com/handwer/p/13816444.html
Copyright © 2011-2022 走看看