Last Train
注意:本题解的点编号从 开始。
作为一个最短路题还是很有意思的。
这道题难点在于让时光倒流,考虑从 出发往各个点走。反向建图,之后就可以用 dijkstra 算法做。
具体一些,先将 初始化为 ,再将 初始化为 (显然从自己到自己无论多晚走都可以)。
再考虑假设目前到达了点 ,从当前点可到 的最晚出发时间为 ,如何计算与之相邻节点的 值?火车从 时刻开始,每隔 发一次车,车程为 。因此,火车会从 开始,每隔 到达一次。显然如果首班车到达时间要早于 就不可能乘坐那班车,可以之间跳过。接着,我们可以计算这班车最晚要坐哪一辆才能赶在 前到达 (具体计算车次即 )。注意,一共只有 班车,因此若 ,你必须乘坐末班车(即 )。有了车次信息,就能计算这趟车的出发时间(),就可以愉快的套进 dijkstra 模板了。
可以发现,本题到达时间晚的点更优,因此堆应当使用大根堆。
#include<bits/extc++.h>
using namespace std;
namespace pbds=__gnu_pbds;
using ui=unsigned int;
using uli=unsigned long long int;
using li=long long int;
struct train{
ui l,d,k,c;size_t a,b;
};
vector<uli> dij(vector<vector<train>> const& mp){
priority_queue<pair<uli,size_t>> q;
q.emplace(numeric_limits<uli>::max(),mp.size()-1);
vector<uli> dis(mp.size(),numeric_limits<uli>::min());
dis.back()=numeric_limits<uli>::max();
vector<bool> vis(mp.size());
while (!q.empty()){
size_t p=q.top().second;q.pop();
if (vis[p]) continue;
vis[p]=true;
for (train const& i:mp[p]){
if (i.l+i.c>dis[p]) continue;
size_t t=(dis[p]-(i.l+i.c))/i.d;
if (t>=i.k) t=i.k-1;
if (i.l+t*i.d>dis[i.a]) q.emplace(dis[i.a]=i.l+t*i.d,i.a);
}
}
return dis;
}
int main(void){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
size_t n,m;cin>>n>>m;
vector<vector<train>> mp(n);
for (size_t i=0;i<m;++i){
train t;cin>>t.l>>t.d>>t.k>>t.c>>t.a>>t.b;--t.a,--t.b;
mp[t.b].push_back(t);
}
vector<uli> ans=dij(mp);
for_each(ans.begin(),prev(ans.end()),[](uli x)
{(x>numeric_limits<uli>::min()?cout<<x:cout<<"Unreachable")<<'\n';});
return 0;
}
浙公网安备 33010602011771号