牛客小白月赛28—H上学要迟到了(最短路)

链接:https://ac.nowcoder.com/acm/contest/7412/H
来源:牛客网

题目描述
牛牛早上起床一看,自己睡过了,赶紧起床准备去学校,他去学校只有两种方式,坐公交车和步行,牛牛去学校是一条直线,这条直线上总共有n个车站,车站之间的距离都是相等的,每个车站只有一种公交车 a i a_i ai,每个公交车只在对应的公交站停车,每个公交车的速度也不一样,第i种公交车过一站的时间需要 t i t_i ti,并且公交车是单向行驶,只能从左到到右,走路可以任意走,然而牛牛自己步行走一站需要的时间为T,恰好牛牛家和学校都在某一个站点,分别为s和t,问最少需要多少时间牛牛才能到学校?

输入描述:
第一行为正整数 n,m,s,t,T 分别表示直线上的车站个数,公交车种数,牛牛家的位置,学校的位置和牛牛自己步行走一站需要的时间 ( n , m ≤ 1 × 1 0 5 , 1 ≤ s , t ≤ n , 1 ≤ T ≤ 1 × 1 0 4 ) (n,m\leq 1×10^5,1\leq s,t\leq n,1\leq T\leq 1×10^4) n,m1×105,1s,tn,1T1×104
第二行有 m 个正整数表示每种公交车过一站需要的时间为 t i ( 1 ≤ t i ≤ 1 × 1 0 4 ) t_i(1\leq t_i \leq 1×10^4) ti1ti1×104
第三行有 nn 个正整数表示每个车站可停的公交车为 a i ( 1 ≤ a i ≤ m ) a_i (1\leq a_i\leq m) ai1aim

输出描述:
输出牛牛从家到学校的最少时间

思路:公交车单向行驶,牛牛可以任意走,所以每一步要么牛牛步行前进或后退一站,要么坐公交车到相应公交车的下一站。根据响应速度建边然后跑一个最短路就好了。

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
#define LL long long
#define uLL unsigned long long
#define PII pair<int,int>
#define mid ((l + r)>>1)
#define chl (root<<1)
#define chr (root<<1|1)
const int manx = 1e5 + 10;
const int INF = 0x3fffffff;
const int mod = 1e4+7;

int n,m,s,t,T,x;
int head[manx],cou=0,cost[manx],p[manx],dis[manx],vs[manx];
struct node{
    int e,len,bf;
}edge[manx<<2];
struct poi{
    int pos,len;
    friend bool operator<(poi a,poi b){
        return a.len>b.len;
    }
};
void add(int s,int e,int len)
{
    edge[cou]=node{e,len,head[s]};
    head[s]=cou++;
}
void init()
{
    memset(head,-1,sizeof head);
    for(int i=1;i<=n;i++){
        dis[i]=2e9;
        vs[i]=0;
    }
}
void dij(int s,int e)
{
    priority_queue<poi>qu;
    dis[s]=0;
    poi now;
    now.len=0,now.pos=s;
    qu.push(now);
    while(!qu.empty()&&vs[e]==0)
    {
        now=qu.top();
        qu.pop();
        if(vs[now.pos])continue;
        vs[now.pos]=1;
        for(int i=head[now.pos];~i;i=edge[i].bf){
            int pos=edge[i].e;
            if(vs[pos])continue;
            if(dis[pos]>now.len+edge[i].len){
                dis[pos]=now.len+edge[i].len;
                qu.push(poi{pos,dis[pos]});
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d%d",&n,&m,&s,&t,&T);
    init();
    for(int i=1;i<=m;i++){
        scanf("%d",&cost[i]);
    }
    memset(p,0,sizeof p);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        if(p[x])
            add(p[x],i,cost[x]);
        p[x]=i;
        if(i<n){
            add(i,i+1,T);
            add(i+1,i,T);
        }
    }
    dij(s,t);
    printf("%d\n",dis[t]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值