Luogu 题解 P5468 【[NOI2019]回家路线】

题目

当时打同步赛时用的暴力dfs,才95分,WA掉1个点。后来想了想,这题可以用SPFA最短路过。

\(dis[x][y]\)表示在\(x\)时间,从\(1\)站点到\(y\)站点的最小烦躁值,就可以用SPFA来做啦~

具体分析看代码:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int n,m,aa,bb,cc;
int anss=999999999;
struct T{
	int u;
	int v;
	int st;
	int ed;//st是开始时间,ed是到达时间
	bool operator <(const T& a) const {
		return u<a.u;
	}//暴力时用的,懒得删掉。
}tr[200010];
int nxt[200010],fst[100010];
bool bo[1001][100001];//标记时间x,站点y有没有到达过。
int dis[1001][100001];//
queue<int>q;//spfa队列,存点
queue<int>tim;//存时间
inline int hs(int x){
	return aa*x*x+bb*x+cc;
}//算烦躁值
int main() {
	memset(dis,0x7f,sizeof(dis));
	scanf("%d%d%d%d%d",&n,&m,&aa,&bb,&cc);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d%d",&tr[i].u,&tr[i].v,&tr[i].st,&tr[i].ed);
		nxt[i]=fst[tr[i].u];
		fst[tr[i].u]=i;//邻接表存图
	}
	q.push(1);
	tim.push(0);
	bo[0][1]=1;
	dis[0][1]=0;//初始化
	while(!q.empty()){
		int x=q.front();
		int ti=tim.front();
		q.pop();
		tim.pop();
		bo[ti][x]=0;
		for(int k=fst[x];k;k=nxt[k]){
			if(tr[k].st<ti) continue;
			if(tr[k].v==n){//判断一下,如果到达n站点还要加上当前时间
				if(dis[tr[k].ed][tr[k].v]>dis[ti][x]+hs(tr[k].st-ti)+tr[k].ed){
					dis[tr[k].ed][tr[k].v]=dis[ti][x]+hs(tr[k].st-ti)+tr[k].ed;
					if(!bo[tr[k].ed][tr[k].v]){
						bo[tr[k].ed][tr[k].v]=1;
						q.push(tr[k].v);
						tim.push(tr[k].ed);
					}
				} 
			}
			else {
				if(dis[tr[k].ed][tr[k].v]>dis[ti][x]+hs(tr[k].st-ti)){//如果在当前火车到达的时间到tr[k].v站点的最小烦躁值大于当前站点的烦躁值,就可以松弛。
					dis[tr[k].ed][tr[k].v]=dis[ti][x]+hs(tr[k].st-ti);
					if(!bo[tr[k].ed][tr[k].v]){
						bo[tr[k].ed][tr[k].v]=1;
						q.push(tr[k].v);
						tim.push(tr[k].ed);
					}
				} 	
			}
		}
	}
	anss=999999999;
	for(int k=1;k<=m;k++){
		if(tr[k].v==n){
			anss=min(anss,dis[tr[k].ed][n]);
		}//判断一下,因为可能有很多个时刻都可以到达终点,需要取最小值。
	}
	cout<<anss;//输出
	return 0;
}


posted @ 2020-01-24 22:39  Yanzy2333  阅读(254)  评论(0)    收藏  举报