[筆記](更新中)最短路問題的變形

Sinktank發表於2024-11-27

\(s\)\(t\)必須經過某個點/某條邊的最短路

這個相當板子了,點\(u\)的答案是\(dis(s,u)+dis(u,t)\),邊\(e=(u,v)\)的答案是\(\min(dis(s,u)+dis(v,t),dis(s,v)+dis(u,t))+w(e)\)。其中\(dis(u,v)\)表示\(u\)\(v\)的最短路。

\(s\)\(t\)各跑一次Dijkstra,其中\(t\)用反圖。預處理出從\(s\)出發和以\(t\)結束的最短路即可。

求最短路數量

P2047 [NOI2007] 社交網路

  • 對於Dijkstra,在鬆弛時,如果\(d[u]+w=d[i]\),則令\(cnt[i]\leftarrow cnt[i]+cnt[u]\);否則令\(cnt[i]\leftarrow cnt[u]\)
  • 對於Floyd,列舉\(i\)\(j\)的中轉點\(k\),如果\(d[i][k]+d[k][j]=d[i][j]\),則令\(cnt[i][j]\leftarrow cnt[i][j]+cnt[i][k]\times cnt[k][j]\);否則令\(cnt[i][j]\leftarrow cnt[i][k]\times cnt[k][j]\)
    • 說明:列舉\(k\)之前的最短路經過的結點都只經過\(1\sim (k-1)\)的點,所以不會重複統計。
Dijkstra 堆最佳化
struct edge{int to,w;};
vector<edge> G[N];
int d[N],cnt[N];
priority_queue<PII,vector<PII>,greater<PII>> q;
void dijkstra(int s){
	memset(d,0x3f,sizeof d);
	memset(cnt,0,sizeof cnt);
	d[s]=0,cnt[s]=1,q.push({0,s});
	while(!q.empty()){
		auto t=q.top();
		int u=t.second;
		q.pop();
		if(t.first>d[u]) continue;
		for(auto i:G[u]){
			if(d[u]+i.w==d[i.to])
				cnt[i.to]+=cnt[u];
			if(d[u]+i.w<d[i.to]){
				d[i.to]=d[u]+i.w;
				q.push({d[i.to],i.to});
				cnt[i.to]=cnt[u];
			}
		}
	}
}
Floyd
for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(f[i][k]+f[k][j]==f[i][j])
				cnt[i][j]+=cnt[i][k]*cnt[k][j];
			else if(f[i][k]+f[k][j]<f[i][j])
				f[i][j]=f[i][k]+f[k][j],
				cnt[i][j]=cnt[i][k]*cnt[k][j];

求兩點間最大邊權的最小值

並不是例題:P2245 星際導航
P2245的雙倍經驗:P1967 [NOIP2013 提高組] 貨車運輸

P2245的正解是(Kruskal重構樹 / 最小生成樹) + LCA,這樣時間複雜度是\(O(m\log m)+O(n\log n)+O(q\log n)\),每次詢問是\(O(\log n)\)的(當然也LCA可以離線求,複雜度上會更優一些)。

上面的題用最短路無法透過,但是在固定起點的情況下,Dijkstra可以做到\(O(m\log m)\)預處理,\(O(1)\)查詢;需要任意兩點間的答案時,Floyd可以\(O(n^3)\)預處理,\(O(1)\)查詢。

  • 對於Dijkstra,重新定義\(f[x]\)為到\(x\)的最大邊權的最小值。鬆弛時,\(f[i]=\min(f[i],\max(f[u],w))\)
    • 初始化時\(f\)設為\(+\infty\)\(f[s]=-\infty\),優先佇列按升序。如果是最小邊權最大則反過來。
  • 對於Floyd,重新定義\(f[i][j]\)\(i\)\(j\)的最大邊權的最小值。轉移時\(f[i][j]=\min(\max(f[i][k],f[k][j]))\)
    • 鄰接矩陣無邊處置為\(+\infty\)。如果是最小邊權最大則反過來。

求每個點到最近關鍵點(可能有多個)的距離

P9432 [NAPC-#1] rStage5 - Hard Conveyors ~ 題解

初始化時,將所有關鍵點的\(d\)設為\(0\),其他設為\(+\infty\),正常跑Dijkstra即可。

同時,也存在非最短路的線性做法,見上面的題解。

相關文章