D107 分层图最短路 Dijkstra 算法 P1266 [BalticOI 2002] 速度限制

D107 分层图最短路 Dijkstra 算法 P1266 [BalticOI 2002] 速度限制_哔哩哔哩_bilibili

 

P1266 [BalticOI 2002] 速度限制 - 洛谷

有向图,边有限速 V 和长度 L,当 V=0 时按前一条边的速度行驶,输出从起点到终点的最短路上的点。

思路

当 (x,y) 边的限速 V=0 时,从 x 点到 y 点的转移与上一条边的限速有关,那么我们把点带上限速转移

也就是把点按限速($V\le500$)拆点,扩展为二维状态,跑分层图最短路

设 d[i][j]​​​ 表示起点到当前点 i,且限速为 j 时所花费的最短时间

当前边的限速=0时,取上一条边的速度松弛;当前边的限速>0时,取当前边的速度松弛

image

相关板子:

D75【模板】分层图最短路 Dijkstra 算法 P4568 [JLOI2011] 飞行路线 - 董晓 - 博客园

 

// 分层图最短路 Dijkstra 算法 O(Mlog(NV))
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;

const int N=155,M=22505;
int idx,h[N],to[M],ne[M],V[M],L[M];
void add(int a,int b,int v,int l){
  to[++idx]=b;V[idx]=v;L[idx]=l;ne[idx]=h[a];h[a]=idx;
}
int n,m,T;
double d[N][505]; int vis[N][505]; pii pre[N][505];

void dijkstra(int s){
  priority_queue<pair<double,pii>> q; //大根堆
  memset(d,126,sizeof d); d[1][70]=0;
  pre[1][70]={0,0};
  q.push({0,{1,70}});
  while(q.size()){
    auto [x,v]=q.top().second; q.pop();
    if(vis[x][v]) continue; vis[x][v]=1;
    for(int i=h[x]; i; i=ne[i]){
      int y=to[i],l=L[i];
      if(V[i]==0 && d[y][v]>d[x][v]+1.0*l/v){ //当前边的限速=0时,取上一条边的速度松弛
        d[y][v]=d[x][v]+1.0*l/v;
        pre[y][v]={x,v};          //记录前驱点
        q.push({-d[y][v],{y,v}}); //当前点的状态入队
      }
      if(V[i] && d[y][V[i]]>d[x][v]+1.0*l/V[i]){ //当前边的限速>0时,取当前边的速度松弛
        d[y][V[i]]=d[x][v]+1.0*l/V[i];
        pre[y][V[i]]={x,v};
        q.push({-d[y][V[i]],{y,V[i]}});
      }
    }
  }
}
void output(int p,int v){
  if(p==0) return;
  output(pre[p][v].first,pre[p][v].second);
  printf("%d ",p-1);
}
int main(){
  cin>>n>>m>>T; T++;
  for(int i=1,a,b,v,l; i<=m; i++){
    cin>>a>>b>>v>>l;
    a++,b++; add(a,b,v,l);
  }
  
  dijkstra(1);
  int v=distance(d[T],min_element(d[T],d[T]+505)); //找出终点最短路的限速
  output(T,v); //回溯输出路径
}

 

posted @ 2026-03-20 22:49  董晓  阅读(51)  评论(0)    收藏  举报