D79 分层图最短路 Dijkstra 算法 CF1473E Minimum Path
D79 分层图最短路 Dijkstra 算法 CF1473E Minimum Path_哔哩哔哩_bilibili
思路
问题是求最短路,一条路径的贡献就是减去一个最大边权,增加一个最小边权
一条路径最多拆分成五段,左图中的两段实线黑边是 max边 或 min边,
如果是 max边就下跳一层,边权为 0;如果是 min边就下跳两层,边权为 2w 
考虑到两种边的先后,需要建四层分层图,按以下方式连边:
- 每层内连双向边,边权为 w
- 第 1 层向第 2 层,第 3 层向第 4 层连单向边,边权为 0(减去 max边)
- 第 1 层向第 3 层,第 2 层向第 4 层连单向边,边权为 2w(增加 min边)
注意:如果两点之间只有一条边,max 和 min 会消去,所以答案要对第 4 层和第 1 层结果取最小值
相关板子:
D75【模板】分层图最短路 Dijkstra 算法 P4568 [JLOI2011] 飞行路线 - 董晓 - 博客园
// 分层图最短路 Dijkstra 算法 O(MlogN) #include<bits/stdc++.h> #define int long long #define pii pair<int,int> using namespace std; const int N=8e5+5,M=4e6; int idx,h[N],to[M],ne[M],ww[M]; void add(int x,int y,int z){ to[++idx]=y,ww[idx]=z,ne[idx]=h[x],h[x]=idx; } int n,m; int d[N]; void dijkstra(){ memset(d,0x3f,sizeof d); d[1]=0; priority_queue<pii,vector<pii>,greater<pii>> q; //小根堆 q.push({0,1}); while(q.size()){ auto [dd,u]=q.top(); q.pop(); if(dd!=d[u]) continue; for(int i=h[u];i;i=ne[i]){ int v=to[i],w=ww[i]; if(d[v]>d[u]+w){ d[v]=d[u]+w; q.push({d[v],v}); } } } } void adde(int x,int y,int z){ add(x,y,z),add(x+n,y+n,z), add(x+2*n,y+2*n,z),add(x+3*n,y+3*n,z); //每层内连边 add(x,y+n,0),add(x+2*n,y+3*n,0); //1层向2层,3层向4层连max型边 add(x,y+2*n,2*z),add(x+n,y+3*n,2*z); //1层向3层,2层向4层连min型边 } signed main(){ scanf("%lld %lld",&n,&m); for(int i=1,x,y,z;i<=m;i++){ scanf("%lld %lld %lld",&x,&y,&z); adde(x,y,z); adde(y,x,z); } dijkstra(); for(int i=2;i<=n;i++)printf("%lld ",min(d[i],d[i+3*n])); }
浙公网安备 33010602011771号