Solution -「CF 575G」Run for beer
阿新 • • 發佈:2020-08-01
\(\mathcal{Description}\)
Link.
給定 \(n\) 個點 \(m\) 條邊的無向圖,邊有邊權,一個人初始速度為 \(1\),每走一條邊速度 \(\div10\),求從 \(1\) 走到 \(n\) 的最小耗時。
\(n,m\le10^5\),\(0\le\text{邊權}\le9\)。
\(\mathcal{Solution}\)
直觀地,路徑長度即為把經過的邊權從低位到高位寫成的十進位制數。
首先排除前導 \(0\)——把從終點出發,僅走邊權為 \(0\) 的邊可達的結點全部與終點縮點。此時的最短路需要保證路徑條數最少的前提下保證字典序最小。BFS 分層,維護當前層外圍最優的一堆結點,用它們向下層擴充套件直到到達起點。
\(\mathcal{Code}\)
#include <queue> #include <cstdio> #include <vector> const int MAXN = 2e5, MAXM = 2e5; int n, m, ecnt, head[MAXN + 5], d[MAXN + 5], suf[MAXN + 5]; bool vis[MAXN + 5]; std::vector<int> curp, nxtp; std::queue<int> que; struct Edge { int to, cst, nxt; } graph[MAXM * 2 + 5]; inline void link ( const int s, const int t, const int c ) { graph[++ ecnt] = { t, c, head[s] }; head[s] = ecnt; } inline void initReach () { for ( int i = 1; i <= n; ++ i ) d[i] = -1; d[1] = 0, que.push ( 1 ); for ( int u; ! que.empty (); ) { u = que.front (), que.pop (); for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( ! ~ d[v = graph[i].to] ) { d[v] = d[u] + 1, que.push ( v ); } } } } inline int zeroReach () { int mind = d[n]; curp.push_back ( n ), vis[n] = true; for ( int cur = 0; cur ^ curp.size (); ++ cur ) { int u = curp[cur]; for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( ! vis[v = graph[i].to] && ! graph[i].cst ) { curp.push_back ( v ), vis[v] = true, suf[v] = u; if ( mind > d[v] ) mind = d[v]; } } } return mind; } int main () { scanf ( "%d %d", &n, &m ); for ( int i = 1, u, v, w; i <= m; ++ i ) { scanf ( "%d %d %d", &u, &v, &w ), ++ u, ++ v; link ( u, v, w ), link ( v, u, w ); } initReach (); int dist = zeroReach (); bool zero = true; for ( int l = dist; l; -- l ) { int dig = 10; for ( int u: curp ) { for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( d[v = graph[i].to] + 1 == l && graph[i].cst < dig ) { dig = graph[i].cst; } } } if ( dig ) zero = false; if ( l == 1 || ! zero ) putchar ( dig ^ '0' ); for ( int u: curp ) { for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( d[v = graph[i].to] + 1 == l && graph[i].cst == dig && ! vis[v] ) { vis[v] = true, nxtp.push_back ( v ), suf[v] = u; } } } curp = nxtp, nxtp.clear (); } if ( zero ) putchar ( '0' ); int ans = 1, u; for ( u = 1; u ^ n; ++ ans, u = suf[u] ); printf ( "\n%d\n0", ans ), u = 1; do printf ( " %d", ( u = suf[u] ) - 1 ); while ( u ^ n ); putchar ( '\n' ); return 0; }