【牛客小白月赛16 】J. 小雨坐地铁
题意:
有\(n\)个站点,\(m\)条地铁线,每条线经过的站点个数为\(c\)个,坐\(i\)号线需要花费\(a_i\)的价格,在第\(i\)号线上每坐一站就要花费\(b_i\)的价格,如果同一站有多条地铁线路,那么可以同站换乘。
现在问从\(s \rightarrow t\)的最小花费是多少。
思路:
可以建一个\(m\)层的最短路,第\(i\)层表示第\(i\)号线的连通状态。
然后根据同站换乘,层与层之间连边,但是这样边数就是\(O(nm^2)\)的。
我们考虑对于每个站建立一个虚点,从地铁线中的点到虚点的代价为\(0\),从虚点到地铁线中的代价为那条地铁线的\(a_i\),然后就把图的规模缩小成了\(O(nm)\)了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define INFLL 0x3f3f3f3f3f3f3f3f
#define N 1000010
int n, m, s, t;
struct Graph {
struct node {
int to, nx, w;
node() {}
node (int to, int nx, int w) : to(to), nx(nx), w(w) {}
}a[N << 1];
int head[N], pos;
void init() {
memset(head, -1, sizeof head);
pos = 0;
}
void add(int u, int v, int w) {
a[pos] = node(v, head[u], w); head[u] = pos++;
}
}G;
#define erp(u) for (int it = G.head[u], v = G.a[it].to, w = G.a[it].w; ~it; it = G.a[it].nx, v = G.a[it].to, w = G.a[it].w)
struct node {
int u; ll w;
node() {}
node(int u, ll w) : u(u), w(w) {}
bool operator < (const node &other) const {
return w > other.w;
}
};
ll dist[N]; bool used[N];
void Dijkstra(int s) {
memset(dist, 0x3f, sizeof dist);
memset(used, 0, sizeof used);
priority_queue <node> pq;
dist[s] = 0;
pq.push(node(s, 0));
while (!pq.empty()) {
int u = pq.top().u; pq.pop();
if (used[u]) continue;
used[u] = 1;
erp(u) if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.push(node(v, dist[v]));
}
}
}
int main() {
while (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF) {
G.init();
for (int i = 1, a, b, c, u, v; i <= m; ++i) {
scanf("%d%d%d", &a, &b, &c);
for (int j = 1; j <= c; ++j) {
scanf("%d", &v);
if (j > 1) {
G.add((i - 1) * n + u, (i - 1) * n + v, b);
G.add((i - 1) * n + v, (i - 1) * n + u, b);
}
G.add((i - 1) * n + v, m * n + v, 0);
G.add(m * n + v, (i - 1) * n + v, a);
u = v;
}
}
Dijkstra(m * n + s);
ll res = dist[m * n + t];
if (res == INFLL) res = -1;
printf("%lld\n", res);
}
return 0;
}

浙公网安备 33010602011771号