圖論最短路之分層圖
阿新 • • 發佈:2020-07-03
一般問題
在圖上,將某一條邊或多條邊進行修改,進而求最短路
變形
包括刪去某一(或多條)條邊(權值變為0),將某一條邊(或多條)減半,將某一條邊進行特殊賦值,求最短路
通用解法
對於k次修改,我們將整張圖複製k次(一般點數和邊數都較小),在單獨的每層圖中,邊權都與原圖相同,不同的是,我們將上下兩層連線起來
如圖(圖片來自洛谷https://www.luogu.com.cn/blog/xiaohou/fen-ceng-tu)
這張圖中將一張圖複製了兩次,即可理解為兩次改變權值,假設我們對圖的修改為將某邊修改為0,一張有向圖中,那麼對於同一層的\(<u_i,v_i>\)其長度等於\(<u_{i-1},v_{i-1}>\)
一道裸題
題目大意
將k條邊變為原來1/2,求最短路
程式碼
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+10; int tot=0; int head[maxn],ver[maxn],next[maxn],dis[maxn]; void add(int x,int y,int z){ ver[++tot]=y,dis[tot]=z,next[tot]=head[x],head[x]=tot; } int n,m,k; priority_queue<pair<int,int> >q; bool v[maxn]; int d[maxn]; void dij(int s){ memset(d,0x3f,sizeof(d)); d[s]=0; q.push(make_pair(0,s)); while(!q.empty()){ int x=q.top().second; q.pop(); if(v[x])continue; v[x]=1; for(int i=head[x];i;i=next[i]){ int y=ver[i],z=dis[i]; if(d[y]>d[x]+z){ d[y]=d[x]+z; q.push(make_pair(-d[y],y)); } } } } main(){ scanf("%d%d%d",&n,&m,&k); int u,v;int dd; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&dd); add(u,v,dd); add(v,u,dd); for(int j=1;j<=k;j++){ add(u+j*n,v+j*n,dd); add(v+j*n,u+j*n,dd); add(u+j*n-n,v+j*n,dd/2); add(v+j*n-n,u+j*n,dd/2); } } dij(1); for (int i = 1; i <= k; i++) d[n] = min(d[n], d[n+n*i]); printf("%d\n", d[n]); }