P1266 速度限制

所谓的“分层图最短路”,但就我目前的理解并没有看出一个分层图的思想在里面。
那么就按图上DP的方式讲。
一开始我想就按一般的方式跑最短路,然后在跑spfa时候队列里面用结构体{x,v}分别表示点和来到它的速度,用x来expand的时候,对于那个被更新的点y,如果x->y是待定的(题目中v=0的)边那么就用{y,v}更新y并推进队列。
看起来比较对,其实是错的,原因就是我们说到底还是在跑最短路,殊不知v可能对y有致命的影响——如果我们发现到y的最短路长是s,可能使s产生的到y的v是一个很小的数,那如果y后面接着一个待定边,可能最终到它的最短路就反而是一个到y的最短路>s的点产生的。应该说清楚了。
那其实应该怎么做呢?说到底是速度的决策有偏颇。而无脑的穷举可以避免决策。因此加维来dp。
设 dis[x][v]表示{在最后一次用速度v的道路到达x}的最短路("{}"内的是修饰词)。
那么
\(vy=0\)\(dis[y][vx]^{\min}_{\longleftarrow}dis[x][vx]+l_{x\to y}/vx\)
\(vy>0\)\(dis[y][vy]^{\min}_{\longleftarrow}dis[x][vx]+l_{x\to y}/vy\)
这样就是对的了
题目要求我们输出路径,考虑怎么记录路径,这里也有一点容易错。
如果我们对y只记录x({使得dis[y][]最优}的到达y的点("{}"内的是修饰词)),然后从d开始跳,那可能会出现这样一种情况,就是我们又违背了“待定路的限速跟前一条路一样”的原则,因为局部最优解可能干扰我们的跳转,因此我们应该定义成fr[y][vy]=(pair<int,int>){x,vx},然后就可以完全地复原我们的更新过程。(每次从一个pair跳到另一个pair。)

// Problem: P1266 速度限制
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1266
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
const int N=155,V=505;
int n,m,d,t,stk[N],inq[N][V];
pair<int,int>fr[N][V];
double dis[N][V];
struct Edge{int y,v,l;};
vector<Edge>G[N];
struct Node{int x,v;};
queue<Node>Q;
int main(){
	cin>>n>>m>>d;d++;
	for(int i=1,x,y,v,l;i<=m;i++){
		cin>>x>>y>>v>>l;x++,y++;
		G[x].push_back((Edge){y,v,l});
	}
	for(int i=1;i<=n;i++)for(int j=0;j<=500;j++)dis[i][j]=1e9;
	Q.push((Node){1,70});inq[1][70]=1,dis[1][70]=0;
	while(!Q.empty()){
		int x=Q.front().x,vo=Q.front().v;Q.pop();inq[x][vo]=0;//if(x==2&&vo==64)cout<<dis[x][vo],puts("H");
		for(int i=0;i<G[x].size();i++){
			int y=G[x][i].y,v=G[x][i].v,l=G[x][i].l;
			if(!v){
				if(dis[y][vo]>dis[x][vo]+1.0*l/vo){
					dis[y][vo]=dis[x][vo]+1.0*l/vo;
					fr[y][vo]=make_pair(x,vo);
					if(!inq[y][vo])inq[y][vo]=1,Q.push((Node){y,vo});
				}
			}
			else if(dis[y][v]>dis[x][vo]+1.0*l/v){
				dis[y][v]=dis[x][vo]+1.0*l/v;
				fr[y][v]=make_pair(x,vo);
				if(!inq[y][v])inq[y][v]=1,Q.push((Node){y,v});
			}
		}
	}
	int x=d,v=0;
	for(int i=1;i<=500;i++)if(dis[x][i]<dis[x][v])v=i;
	while(x){
		stk[++t]=x;
		pair<int,int>tmp=fr[x][v];
		x=tmp.first,v=tmp.second;
	}
	while(t)cout<<stk[t--]-1<<' ';
}
posted @ 2021-11-14 21:21  pengyule  阅读(75)  评论(0)    收藏  举报