D、小雨坐地铁
分层建图,求单源最短路,不带负权边。
如果单看最短路,不带负权边,很容易想到迪杰斯特拉算法,那么还有一个主要问题就是这个图怎么建立了。
我们知道对于一条地铁线,存在最大N个结点,如果不够也没关系,我们对这一条地铁线上的点进行建边,假设第一条地铁线在第一层,花费为地铁一站的花费,那么第二条地铁线在第二层,这层地铁线可能也用到了第一层某个站点,我们就要对应在M+1层开一个超级源点,从站点去超级源点假设花费为0,那么从超级源点去往某一条地铁线中的点就是转线或者上地铁了,花费记作上地铁的花费。
那么我们的迪杰斯特拉算法就变成了,从超级源点中的起点,去往超级源点中的终点。存在的最短路,直接求解即可,判断是否小于等于初始化的INF,直接输出答案就OK了。
vector相比于前向星码量小,适合我这种懒人,卡vector的 坑爹 良心出题人想让我们多用用更好的方案
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=43533955
#include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; inline int read() { int s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } const int N = 5e5+3e3; //节点数 const int M = 5e5 + 7; //路径数 const ll INF = 1e18; ll d1[N]; struct Node { int v; ll cost; bool operator < (Node b)const { return cost > b.cost; } }; vector<Node> e[N]; int n, m, st, ed; void dijkstra(int s, ll d[]) { priority_queue<Node> pq; fill(d, d + N, INF); d[m * n + s] = 0; pq.push(Node{ m * n + s,0 }); while (!pq.empty()) { Node x = pq.top(); pq.pop(); if (d[x.v] < x.cost) continue; //原先这个节点花费更少 跳过 for (auto it : e[x.v]) { if (d[it.v] > x.cost + it.cost) { d[it.v] = x.cost + it.cost; pq.push(Node{ it.v,d[it.v] }); } } } } int main() { n = read(), m = read(); st = read(), ed = read(); for (int i = 0; i < m; ++i) { int a = read(), b = read(), c = read(), x = read(); e[i * n + x].push_back(Node{ m * n + x, 0 }); e[m * n + x].push_back(Node{ i * n + x, a }); while (--c) { int y = read(); e[i * n + x].push_back(Node{ i * n + y, b }); e[i * n + y].push_back(Node{ i * n + x, b }); e[i * n + y].push_back(Node{ m * n + y, 0 }); e[m * n + y].push_back(Node{ i * n + y, a }); x = y; } } dijkstra(st, d1); if (d1[m * n + ed] == INF) puts("-1"); else printf("%lld\n", d1[m * n + ed]); return 0; }