拯救小tim

【问题描述】
小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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值