牛客算法周周练5 D 小雨坐地铁
题目
分析
这样的题目很容易想到 分层图 和 最短路, 而这类型的题目, 重点主要在建图上.
分层图中, 每一层自然是每一条地铁线路, 这个好说. 那层与层之间, 怎样建立关系呢?
可以这样理解吧, 将一个站台分成不同区域, 一个中转区, 多个(如果有的话)不同线路地铁的站台.
那么接下来就好说了.
从这个中转区到这一点其他站台, 都要交相应的车费 , 而从每个站台下车到中转区, 是不花钱的.
于是, 可以在额外的一层图中, 建立 n 个虚点, 即 n 个中转区, 连接该点所有的站台.
至此, 这个问题就解决了.
代码
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <functional> #include <utility> using namespace std; const int SIZE = 1e6; const int INF = 0x3f3f3f3f; struct Edge { int end; int weight; int next; }; Edge edge[SIZE]; int head[SIZE]; int edgestamp; int dis[SIZE]; bool flag[SIZE]; priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > heap; void addEdge(int u, int v, int w); void dijkstra(int source); int main() { int n, m, s, t; int a, b, c; int u, v; // freopen("cpp.in", "r", stdin); scanf("%d %d %d %d", &n, &m, &s, &t); for (register int i = 1; i <= m; i++) { scanf("%d %d %d", &a, &b, &c); for (register int j = 1; j <= c; j++) { scanf("%d", &v); if (j > 1) { addEdge((i - 1) * n + u, (i - 1) * n + v, b); addEdge((i - 1) * n + v, (i - 1) * n + u, b); } addEdge((i - 1) * n + v, m * n + v, 0); addEdge(m * n + v, (i - 1) * n + v, a); u = v; } } dijkstra(m * n + s); if (dis[m * n + t] < INF) printf("%d\n", dis[m * n + t]); else printf("-1\n"); // fclose(stdin); return 0; } void addEdge(int u, int v, int w) { edge[++edgestamp].end = v; edge[edgestamp].weight = w; edge[edgestamp].next = head[u]; head[u] = edgestamp; } void dijkstra(int source) { int u, v, w; memset(dis, 0x3f, sizeof(dis)); memset(flag, false, sizeof(flag)); dis[source] = 0; heap.push(make_pair(dis[source], source)); while (!heap.empty()) { u = heap.top().second; heap.pop(); if (flag[u]) continue; flag[u] = true; for (register int i = head[u]; i != 0; i = edge[i].next) { v = edge[i].end; w = edge[i].weight; if (dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if (!flag[v]) heap.push(make_pair(dis[v], v)); } } } }