D79 分层图最短路 Dijkstra 算法 CF1473E Minimum Path

D79 分层图最短路 Dijkstra 算法 CF1473E Minimum Path_哔哩哔哩_bilibili

 

CF1473E Minimum Path - 洛谷

思路

问题是求最短路,一条路径的贡献就是减去一个最大边权,增加一个最小边权

一条路径最多拆分成五段,左图中的两段实线黑边是 max边 或 min边,

如果是 max边就下跳一层,边权为 0;如果是 min边就下跳两层,边权为 2w   image

考虑到两种边的先后,需要建四层分层图,按以下方式连边:

  1. 每层内连双向边,边权为 w
  2. 第 1 层向第 2 层,第 3 层向第 4 层连单向边,边权为 0(减去 max边)
  3. 第 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]));
}

 

posted @ 2026-02-19 22:26  董晓  阅读(139)  评论(0)    收藏  举报