【问题描述】
小tim在游乐场,有一天终于逃了出来!但是不小心又被游乐场的工作人员发现了。。。 所以你的任务是安全地把小tim护送回家。
但是,A市复杂的交通状况给你除了一个难题。
A市一共有n个路口,m条单行马路。但是,每条马路都只有一段时间是开放的。为了 安全,你必须选择一条护送路线,使得小
tim在路上的时间最短,即到家的时刻减去离开游
乐场的时刻最短。
【样例解释】
最优方案应该是,在1号点停留至时刻1,然后走到3号点,然后走到4号点。到达时 刻为时刻4。在路上的时间为4-1=3。
【输入格式】
第一行4个数,分别是n,m,s,t(2<=n<=100;0<=m<=1000;1<=s,t<=n,s≠t)。基地在路口s,码头在路口t。
接下来m行每行5个数x,y,b,e,c 表示一条x路口到y路口的单行线,在b时刻到e时刻之间开放,需要c的时间通过这条路
(必须保证行进在路中间时,路一直开放,否则小tim会被捉住)。两个路口之间可能会有多条道路。一开始的时刻是0(当然
,你可以不用马上出发,在基地多呆一段时间)。
如果不存在任何一种方案使得小tim能成功到达码头,输出“Impossible”。
【输出格式】
一行,为小tim在路上停留的最短时间
Sample Input
4 5 1 4
1 2 0 1 1
1 2 0 1 2
1 3 1 3 2
2 4 3 4 1
3 4 3 4 1
Sample Output
3
解题思路:
一道非常巧妙的SPFA题目。我们可以按照时间点进行SPFA。
1.首先,如果到了当前节点而当前的路还没有开放,那就应该按照开放的时间点向下走,如果开放了而晚到了,那就按晚到的时间,所以应该取max。
2.按照出发的时间点进行spfa,取最早的出发点和最晚的出发点进行SPFA。
3.SPFA时,点能进入队列有两个条件:1.在道路关闭之前到达。2.时间最短。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
queue<int>q;
struct node{
int from,to,l,r,ds;
}list[1005];
int minn,k,maxx=-1e9,n,m,s,t,x,y,l,r,c,ans;
int head[1005],dis[1005],v[1005];
void add(int x,int y,int l,int r,int c){
list[++k].from=head[x];
list[k].to=y;
list[k].l=l;
list[k].r=r;
list[k].ds=c;
head[x]=k;
}
void spfa(int x){
memset(dis,127/3,sizeof(dis));
memset(v,0,sizeof(v));
q.push(s);dis[s]=x;v[s]=1;
while(!q.empty()){
int u=q.front();q.pop();v[u]=0;
for (int i=head[u];i;i=list[i].from){
if (max(dis[u],list[i].l)+list[i].ds<=list[i].r)
if (max(dis[u],list[i].l)+list[i].ds<dis[list[i].to]){
dis[list[i].to]=max(dis[u],list[i].l)+list[i].ds;
if (!v[list[i].to]){
v[list[i].to]=1;
q.push(list[i].to);
}
}
}
}
}
int main(){
cin>>n>>m>>s>>t;
ans=minn=1e9;
for (int i=1;i<=m;i++){
scanf("%d%d%d%d%d",&x,&y,&l,&r,&c);
if (l>r) swap(l,r);
if (l+c>r) continue;
if (x==s){
minn=min(minn,l);
maxx=max(maxx,r-c);
}
add(x,y,l,r,c);
}
for (int i=minn;i<=maxx;i++){
spfa(i);
if (dis[t]==dis[0]) break;//优化,如果某一时刻到达不了,那后来的也就到达不了了。
ans=min(ans,dis[t]-dis[s]);
}
if (ans==1e9) cout<<"impossible";
else
cout<<ans;
return 0;
}