版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/richenyunqi/article/details/89640019
欢迎访问我的Uva题解目录哦 https://blog.csdn.net/richenyunqi/article/details/81149109
题目描述
题意解析
在一个赛车比赛中,赛道有n(n≤300)个交叉点和m(m≤50000)条单向道路。有趣的是:每条路都是周期性关闭的。每条路用5个整数u, v, a, b, t表示
表示起点是u,终点是v,通过时间为t秒。另外,这条路会打开a秒,然后关闭b秒,然后再打开a秒,依此类推。当比赛开始时,每条道路刚刚打开。你的赛车必须在道路打开的时候进入该道路,并且在它关闭之前离开(进出道路不花时间,所以可以在打开的瞬间进入,关闭的瞬间离开)。
你的任务是从s出发,尽早到达目的地t
。道路的起点和终点不会相同,但是可能有两条道路的起点和终点分别相同。
算法设计
使用Dijkstra算法,注意在计算一个结点u出发的边权时要考虑等待时间即可。
C++代码
#include<bits/stdc++.h>
using namespace std;
struct Edge{
int from,to,cost,open,close;
Edge(int f,int t,int o,int clo,int c):from(f),to(t),open(o),close(clo),cost(c){}
};
const int MAXV=305;
vector<Edge>edges;
vector<int>graph[MAXV];
int n,m,s,t,dis[MAXV];
int arriveNext(int arrive,const Edge&e){//计算从到达道路e起点的时间arrive到达道路e终点时间
int temp=arrive%(e.open+e.close);
if(temp+e.cost<=e.open)
return arrive+e.cost;
return arrive+e.open+e.close-temp+e.cost;
}
void Dijkstra(){
using pii=pair<int,int>;
priority_queue<pii,vector<pii>,greater<pii>>pq;//pii的first成员存储dis,second成员存储结点编号
fill(dis,dis+MAXV,INT_MAX);
dis[s]=0;
pq.push({0,s});
while(!pq.empty()){
pii p=pq.top();
pq.pop();
if(dis[p.second]!=p.first)
continue;
for(int i:graph[p.second]){
Edge&e=edges[i];
int arrive=arriveNext(dis[p.second],e);//到达道路e终点的时间
if(dis[e.to]>arrive){
dis[e.to]=arrive;
pq.push({dis[e.to],e.to});
}
}
}
}
int main(){
for(int ii=1;~scanf("%d%d%d%d",&n,&m,&s,&t);++ii){
edges.clear();
fill(graph,graph+n+1,vector<int>());
while(m--){
int u,v,a,b,t;
scanf("%d%d%d%d%d",&u,&v,&a,&b,&t);
if(t>a)//如果通过该路的用时比该路的开放时间还要长,直接忽略该路
continue;
graph[u].push_back(edges.size());
edges.push_back(Edge(u,v,a,b,t));
}
Dijkstra();
printf("Case %d: %d\n",ii,dis[t]);
}
return 0;
}