分層圖最短路[學習筆記]
阿新 • • 發佈:2020-07-31
分層圖最短路,主要是用來求解允許少量次數修改邊權的最短路問題,由於修改此數較小,所以解法也有些許暴力.下面,讓我們來看這麼一道例題:
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]); }