1. 程式人生 > 實用技巧 >分層圖最短路[學習筆記]

分層圖最短路[學習筆記]

分層圖最短路,主要是用來求解允許少量次數修改邊權的最短路問題,由於修改此數較小,所以解法也有些許暴力.下面,讓我們來看這麼一道例題:

description:

有一\(n\)\(m\)邊構成的連通圖,給定起點\(S\)和終點\(T\),現允許你將至多\(k(k\leq10)\)條邊的邊權修改為\(0\),請你求出修改次數不超過\(k\)的情況下,\(S\)\(T\)的最短路徑長度.

solution:

此題是分層圖最短路模板題.首先不難想到一一列舉\(k\)條免費邊,然後跑最短路,但演算法複雜度\(O((m+n)logn \cdot\C_{m}^{k})\),極度暴力,連最小資料範圍都十分吃力,於是我們便需引入新的思路.

由於\(k\)較小,我們不妨構造\(k+1\)個相同的聯通圖,其中第\(i\)\(i+1\)個連通圖中對應的邊我們連上權值為\(0\)的單向邊,以表示免費的邊.用此方式,每次只能跑向層數更高的圖,或在本層圖內跑.且每跑進一個新圖,意味著我們跑過了一條免費邊,所以構造該分層圖可以完美求解本題.答案即為每層終點的最短路的最小值,為方便起見,我們可以在每層終點向下一層終點連一條權值為\(0\)的單向邊以傳遞最短路,最後輸出最後一層終點的答案即可.

code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define mod 1004535809
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
ll n,m,k;
ll head[3000000],next[3000000],to[3000000],w[3000000],tot;
ll S,T;
ll d[3000000];
bool vis[3000000];

inline void add(ll x,ll y,ll z){to[++tot]=y;next[tot]=head[x];head[x]=tot;w[tot]=z;}

//queue<ll>q;
//inline void spfa(){
//	memset(d,0x3f,sizeof d);
//	q.push(S);d[S]=0;
//	while(q.size()){
//		ll x=q.front();q.pop();vis[x]=false;
//		for(R ll i=head[x],ver;i;i=next[i]){
//			ver=to[i];
//			if(d[ver]>d[x]+w[i]){
//				d[ver]=d[x]+w[i];
//				if(!vis[ver]){
//					vis[ver]=true;
//					q.push(ver);
//				}
//			}
//		}
//	}
//}

ll ans;
priority_queue<pair<ll,ll> >q;
inline void dijkstra(){
	memset(d,0x3f,sizeof d);
	d[S]=0;;
	q.push(make_pair(0,S));
	while(q.size()){
		ll x=q.top().second;q.pop();
		if(vis[x]) continue;
		vis[x]=true;
		for(R ll i=head[x],ver;i;i=next[i]){
			ver=to[i];
			if(d[ver]>d[x]+w[i]){
				d[ver]=d[x]+w[i];
				q.push(make_pair(-d[ver],ver));
			}
		}
	}
}

int main(){	
	n=read();m=read();k=read();
	S=read()+1;T=read()+1;
	while(m--){
		ll x=read()+1,y=read()+1,z=read();
		add(x,y,z);add(y,x,z);
		for(R ll i=1;i<=k;i++){
			add(x+i*n,y+i*n,z);add(y+i*n,x+i*n,z);
			add(x+(i-1)*n,(y+i*n),0);
			add(y+(i-1)*n,(x+i*n),0);
		}
	}
	for(R ll i=1;i<=k;i++){
		add(T+(i-1)*n,T+i*n,0);
	}
//	spfa();
	dijkstra();
	writeln(d[T+n*k]);
}