题意:

有n个点,m条地铁线,每条地铁线有一个三个值,分别表示这条地铁线上车的费用,坐一站的费用,和这条地铁线包含几个点,现在你需要从第 s 个地铁站到达第 t 个地铁站,问你至少需要花费多少钱?

做法:

和之前两个题目一样的做法,分层图最短路,不过这里的代码实现采用建虚点的方式,也就是说,对于每个点,我们将他在m个地铁线上的时候看作不一样的点,并且额外定义一个虚点表示下车,从m个地铁线上的点走到对应的虚点表示下车,不需要花钱,反之,表示上车,需要花费对应地铁线的上车费,建图完成之后直接跑最短路即可得到最小花费。

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 6e5;
const ll mod = 1e9 + 7;
const ll inf = 1e18 + 7;
struct edge
{
    int to;
    ll w;
    int nex;
}e[MAXN * 2];
int head[MAXN], tot;
ll dis[MAXN];
bool vis[MAXN];
void init()
{
    memset(head, -1, sizeof(head));
    tot = 1;
    for (int i = 0; i < MAXN; i++)
        dis[i] = inf;
}
void add(int a, int b, ll c)
{
    e[tot] = edge{ b,c,head[a] };
    head[a] = tot++;
}
#define Pair pair<int,int>
void dij(int s)
{
    priority_queue<Pair, vector<Pair>, greater<Pair> >q;
    q.push(Pair{ 0,s });
    dis[s] = 0;
    while (!q.empty())
    {
        int u = q.top().second;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = true;
        for (int i = head[u]; i + 1; i = e[i].nex)
        {
            int v = e[i].to;
            if (dis[v] > dis[u] + e[i].w)
            {
                dis[v] = dis[u] + e[i].w;
                q.push(Pair{ dis[v],v });
            }
        }
    }
}
int n, m, s, t;
int in[1005];
int main()
{
    init();
    scanf("%d%d%d%d", &n, &m, &s, &t);
    int a, b, cnt;
    for (int i = 0; i < m; i++)
    {
        scanf("%d%d%d", &a, &b, &cnt);
        for (int j = 0; j < cnt; j++)
        {
            scanf("%d", &in[j]);
            if (j > 0)
            {
                add(i * n + in[j - 1], i * n + in[j], b);
                add(i * n + in[j], i * n + in[j - 1], b);
            }
            add(i * n + in[j], m * n + in[j], 0);
            add(m * n + in[j], i * n + in[j], a);
        }
    }
    dij(m * n + s);
    if (dis[m * n + t] == inf)
        dis[m * n + t] = -1;
    printf("%lld\n", dis[m * n + t]);
}