csp-j2023第四题 旅游巴士
旅游巴士这道题在一年之前的csp-j中并没有做(我是一个蒟蒻)
回看本题,又有了新的想法
对于每一层i我们将其看成走到这是的时间j mod k的余数
很显然,为了让我们更快的通过,等待时间+当前时间>=限制时间是最优的
/*
使用分层图,跑dijkstra堆优化的最短路
在限制时间那部分,若小于限制时间,可每次等k的倍数的时间,使得:等待时间+当前时间>=限制时间
因为离开时间是k的倍数,所以我们尽量使每次到达一个点的时间也是k的倍数,这样离开时就不用再等太久了
按照上述思路敲代码是最优的
vector数组graph是用来存储分层图的,为graph_node类型的
min_time[i]表示走到分层图的第i个节点的最优时间
q 是优先队列(堆)priority_queue,是graph_node结构体为类型的,进行重载小于号,方便堆排序
时间复杂度 O(nk log(nk))
*/
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct graph_node{
int to_node;
int cur_time;
bool operator<(const graph_node &s1)const{
return cur_time>s1.cur_time;
}
};
vector<graph_node>graph[N];
int n,m,k;
int min_time[N];
void dijkstra(int start){
for (int i=1;i<=n*k;i++)min_time[i]=0x3f3f3f3f;
priority_queue<graph_node>q;
q.push({start,0});min_time[1]=0;
while (!q.empty()){
int cur=q.top().to_node,t=q.top().cur_time;q.pop();
if (t<=min_time[cur]){
for (const auto&road:graph[cur]){
int plat=min_time[cur]+1,limt=road.cur_time;
if (min_time[cur]<limt)plat+=ceil((limt-min_time[cur])*1.0/k)*k;
if (plat<min_time[road.to_node]){
min_time[road.to_node]=plat;
q.push({road.to_node,plat});
}
}
}
}
}
int main(){
cin>>n>>m>>k;
int x,y,len;
for (int i=1;i<=m;i++){
cin>>x>>y>>len;
for (int j=0;j<k;j++)
graph[j*n+x].push_back({(j+1)%k*n+y,len});
}
dijkstra(1);
if (min_time[n]==0x3f3f3f3f)cout<<-1;
else cout<<min_time[n];
return 0;
}