【题解】Luogu P3259 [JLOI2014] 路径规划

首先计算在红绿灯 \((a,b)\) 处期望的等待时间。记 \(a+b\) 为一个周期(即先有时长为 \(a\) 的红灯,再有时长为 \(b\) 的绿灯),设我们在 \(x\) 时刻到达了这个红绿灯,那么我们需要等待的时间显然为 \(\max(a-x,0)\)

要求出期望,就要用上面那个函数的和再除以总时长,也就是 \(\frac{a^2}{2(a+b)}\)。于是这道题就变成了一道普通的图论问题。

考虑分层图,一共建 \(k+1\) 层图,在每个红绿灯处向上一层连边。考虑答案路径,一定是从起点开始再若干个加油站加油再走到终点的过程,而加油站与加油站之间怎么走我们是不用管它的。那么我们就以每个加油站为起点跑最短路,将所有加油站抽出来,在限制内能走到另一个加油站就在新图上连边。最后再在新图上跑一次最短路即可。

时间复杂度 \(O(50kn\log kn)\)

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define id(x,y) ((x)+n*((y)-1))
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=2e5+5;
int n,m,_k,lim,cst;
double dis[maxn],out[maxn];
bool gas[maxn],vis[maxn];
map<string,int> hao;
vector<pair<int,double> > e1[maxn],e2[maxn];
priority_queue<pair<double,int> > q;
il void dijkstra(int s,auto &e){
	for(int i=1;i<=n*(_k+1);i++){
		dis[i]=1e18,vis[i]=0;
	}
	dis[s]=0,q.push(mp(0,s));
	while(q.size()){
		int u=q.top().sec;
		q.pop();
		if(vis[u]){
			continue;
		}
		vis[u]=1;
		for(auto i:e[u]){
			int v=i.fir;
			double w=i.sec;
			if(!vis[v]&&dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(mp(-dis[v],v));
			}
		}
	}
}
namespace cplx{
	bool end;
	il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m>>_k>>lim>>cst;
	for(int i=1,a,b;i<=n;i++){
		string s;
		cin>>s>>a>>b;
		hao[s]=i;
		gas[i]=~s.find("gas");
		if(a){
//			cout<<i<<"\n";
			out[i]=a*1.0*a/2/(a+b);
		}
	}
	int st=hao["start"],ed=hao["end"];
	for(int i=1,u,v,w;i<=m;i++){
		string a,b,c;
		cin>>a>>b>>c>>w;
		u=hao[a],v=hao[b];
		for(int j=1;j<=_k+1;j++){
			if(out[u]){
				if(j<=_k){
					e1[id(u,j)].pb(mp(id(v,j+1),w+out[u]));
				}
			}
			else{
				e1[id(u,j)].pb(mp(id(v,j),w));
			}
			if(out[v]){
				if(j<=_k){
					e1[id(v,j)].pb(mp(id(u,j+1),w+out[v]));
				}
			}
			else{
				e1[id(v,j)].pb(mp(id(u,j),w));
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(i==st||gas[i]){
//			cout<<i<<"---";
			dijkstra(i,e1);
			for(int j=1;j<=n;j++){
				if(gas[j]){
					for(int k=1;k<=_k+1;k++){
						if(dis[id(j,k)]<=lim){
							for(int x=1,y=k;y<=_k+1;x++,y++){
								e2[id(i,x)].pb(mp(id(j,y),dis[id(j,k)]+cst));
//								cout<<id(i,x)<<" "<<id(j,y)<<" "<<dis[id(j,k)]+cst<<"\n";
							}
						}
					}
				}
				else if(j==ed){
					for(int k=1;k<=_k+1;k++){
						if(dis[id(j,k)]<=lim){
							for(int x=1,y=k;y<=_k+1;x++,y++){
								e2[id(i,x)].pb(mp(id(j,y),dis[id(j,k)]));
//								cout<<id(i,x)<<" "<<id(j,y)<<" "<<dis[id(j,k)]<<"\n";
							}
						}
					}
				}
			}
		}
	}
	dijkstra(st,e2);
	double ans=1e18;
	for(int i=1;i<=_k+1;i++){
//		cout<<dis[id(ed,i)]<<"\n";
		ans=min(ans,dis[id(ed,i)]);
	}
	printf("%.3f",ans);
	return 0;
}
}
int main(){return asbt::main();}
posted @ 2025-03-08 15:57  zhangxy__hp  阅读(24)  评论(0)    收藏  举报