分层图,建图,最短路

题意:

图片说明

分析:

首先来看看我当时的思路吧!

我们很容易发现这是个最短路问题,但线路的存在很棘手。雨神说过,图论的难点在于建图!如果成功建图接下来就只是套板子了。那来看看我们如何建图。
我上来也没有思路,后是从实际生活入手的。
想象一下,我们在站点i我们可以坐1,2,3三路高铁,登上1号高铁掏钱a1,登上2号高铁掏钱a2,登上3号高铁掏钱a3
然后我们登上了高铁,假设我们登上了高铁1号线,我们向前开开了一站到达了j站的高铁上,这时我们要在花费b1然后我们从j站的高铁上下来,不用掏钱。

从i站到j站是不是就是这个过程。那我们就模仿这个过程建图就好了嘛。
除了站点之外,我们再建立一个高铁站不就好了,从站点跑上高铁站要是收费,从高铁站跑下站点不要收费。
高铁站线路移动的消耗为b

以样例为例:
5 2 1 4
2 2 3 1 3 5
2 1 4 2 3 4 5

第一条线路:(我们以6,7,8来表示高铁站)
图片说明
第二条线路:(我们以9,10,11来表示高铁站)
图片说明
那么合起来就是:
图片说明

是不是,我们完美的模仿了高铁的功能,并且没有添加其他的功能。
如此我们便解决了这个问题!
在遍历每条线路时,对遍历的点给他建一个高铁站,这条线路遍历完后,对此线路的高铁站再建双向边。
最后再用dijstra算法就完事了。

代码如下:

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
struct edge { int to, cost; };
const int max_n = 7e5;
const ll inf = 2e18;
vector<edge> G[max_n];
ll d[max_n];
int n, m;

void dijstra(int s) {
    fill(d + 1, d + 1 + n, inf);
    priority_queue<pll,vector<pll>,greater<pll>> que;
    d[s] = 0;que.push({ d[s],s });
    while (!que.empty()) {
        pll p = que.top();que.pop();
        if (p.first > d[p.second])continue;
        d[p.second] = p.first;
        for (int i = 0;i < G[p.second].size();i++) {
            edge e = G[p.second][i];
            if (d[e.to] > d[p.second] + e.cost) {
                d[e.to] = d[p.second] + e.cost;
                que.push({ d[e.to],e.to });
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    int s, t;
    cin >> n >> m >> s >> t;
    for (int i = 1;i <= m;i++) {
        int a, b, c;cin >> a >> b >> c;
        int st = n + 1;
        for (int j = 1;j <= c;j++) {
            int node;cin >> node;n++;
            G[n].push_back({ node,0 });
            G[node].push_back({ n,a });
        }
        for (int j = st;j < n;j++) {
            G[j].push_back({ j + 1,b });
            G[j + 1].push_back({ j,b });
        }
    }
    dijstra(s);
    if (d[t] == inf)cout << -1 << endl;
    else cout << d[t] << endl;
}

做完,来看题解后才发现这是一种被称为分层图的问题。不说了,去研究研究