【JLOI2011】飞行路线

题目描述

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

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

输入格式

数据的第一行有三个整数,n,m,kn,m,k,分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,s,ts,t,分别表示他们出行的起点城市编号和终点城市编号。
接下来有m行,每行三个整数,a,b,ca,b,c,表示存在一种航线,能从城市aa到达城市bb,或从城市bb到达城市aa,价格为cc。

输出格式

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

输入 #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

【解题思路】

分层图模板题

我们将每个点拆成k个,这样子在路径上就能够表现出,选择简化这个点到另外一个点的路径对结果的影响

因为刚好是k层,所以能够优化的路径也就至多只有k层,保证了选择k条路径的前提

有点 u ,v ,令第 j - 1 层的 u 到第 j 层的 v 连边,代价为 0 ,这样子就能够表示这条路径被优化,同时又消耗了一次免费机会

注意:因为是双向边,所以同时也要连一条反向边

第 j 层的 u ,v 同时也要连一条边,代价为 c ,令优化过的 u 能够在不优化的情况下到达 v

得到这个新的图之后,我们在上面跑一遍最短路,就能够得到正确结果

因为最短路已经利用所有的 k 次机会优化了整个过程

 

【代码】

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define ll long long 
using namespace std;
typedef pair<int, int> P;
const int MAXN = 110010;
const int MAXM = 4100010;
const ll  INF = (1ll << 62) - 1;
struct note
{
    int to;
    int nt;
    ll cost;
};
struct edge
{
    note arr[MAXM];
    int  st[MAXN];
    ll  dis[MAXN];
    int  top;
    int n, m, s, t,k;
    edge()
    {
        memset(st, -1, sizeof(st));
        memset(dis, -1, sizeof(dis));
        top = 0;
    }
    void read()
    {
        top = 0;
        scanf("%d%d%d", &n, &m, &k);
        scanf("%d%d", &s, &t);
        s++, t++;
        for (int i = 1; i <= m; i++)
        {
            int u, v;
            ll c;
            scanf("%d%d%lld", &u, &v, &c);
            u++, v++;
            add(u, v, c);
            add(v, u, c);
            for (int j = 1; j <= k; j++)
            {
                add(u+( j - 1 )*n, v + j*n, 0);
                add(v+( j - 1 )*n, u + j*n, 0);
                add(u + j * n, v + j * n, c);
                add(v + j * n, u + j * n, c);
            }
        }
        for (int i = 1; i <= k; ++i)
        {
            add(t + (i - 1)*n, t + i * n,0);
        }
        t += k * n;
        n = n * (k+1)+1;
    }
    void add(int x, int y, ll c)
    {
        top++; arr[top] = { y,st[x],c }; st[x] = top;
    }
    ll min_dis()
    {
        priority_queue<P,vector<P>,greater<P> > q;
        fill(dis+1, dis + n+1, INF);
        dis[s] = 0;
        q.push(P(0, s));
        while (!q.empty())
        {
            P p = q.top();q.pop();
            int v = p.second;
            if (dis[v] < p.first)    continue;
            for (int i = st[v]; i != -1; i = arr[i].nt)
            {
                int to = arr[i].to;
                if (dis[to] > dis[v] + arr[i].cost)
                {
                    dis[to] = dis[v] + arr[i].cost;
                    q.push(P(dis[to], to));
                }
            }

        }
        return dis[t];
    }
};
edge road;
int main()
{
    road.read();
    printf("%lld", road.min_dis());
    return 0;
}
View Code

 

 
 
posted @ 2019-08-08 13:39  rentu  阅读(260)  评论(0编辑  收藏  举报