有 \(n\) 點 \(m\) 邊的帶權無向圖(\(n\le 10^5; m \le 2\times10^5\))。你可以指定一條 \(s-t\) 的最短路使其邊權歸零,求 \(u-v\) 的最短路徑。
作法
考慮將無向圖拆成有向圖。存在 \(stDAG\) 的任何完整路徑(從入度為零的點開始,走到出度為零的點為止)都是 \(s-t\) 最短路。
答案有三種可能:
- 不經過 \(s-t\) 最短路,\(ans = dis(u,v)\)
- \(u\) 從 \(x\) 接入 \(stDAG\),從 \(y\) 離開 \(stDAG\) 前往 \(v\),\(ans = dis(u,x)+dis(y,v)\)
- \(v\) 從 \(x\) 接入 \(stDAG\),從 \(y\) 離開 \(stDAG\) 前往 \(u\),\(ans = dis(v,x)+dis(y,u)\)
想找出 \(dis(v,x)\) 和 \(dis(y,u)\) 只要從 \(u,v\) 分別作 Dijkstra 即可。
如何找到 \(x, y\) ?
考慮在 \(stDAG\) 上 DP:
- \(dpu[i]\) 代表 \(path(s,i)\) 上最小的 \(dis(u,i)\)
- \(dpv[i]\) 代表 \(path(s,i)\) 上最小的 \(dis(v,i)\)
則將 \(i\) 作為 \(y\) 的答案即為 \(min(dpu[prev]+dis(v,i), dpv[prev]+dis(u,i))\)。
如何在 \(stDAG\) 上 DP?
對於正邊權圖,只要維護 \(vis\) 使得每個點只會被拿出來一次,Dijkstra 拿出來的順序就是在單源最短路 DAG 上的拓樸排序。
因此我們可以從 \(s\) 做一次 Dijkstra ,在 \(sDAG\) 上得到 \(dpu\) 和 \(dpv\)。
若我們在 \(sDAG\) 的反圖 \(sDAG'\) 上從 \(t\) 做 BFS 相當於在 \(tsDAG\) BFS。此時任一節點 \(i\),後繼節點為 \(j\),則將 \(i\) 作為 \(y\) 的答案是 \(min(dpu[j]+dis(v,i), dpv[j]+dis(u,i))\)
BFS 不用另外寫,直接重複使用 Dijkstra 即可(被拿出來的順序不重要)。
AC Code
1 |
|