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时,取当前边的速度松弛

相关板子:
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); //回溯输出路径 }
浙公网安备 33010602011771号