2023年CSP入门级第二轮第四题——旅游巴士

概要

题目描述

小 Z 打算在国庆假期期间搭乘旅游巴士去一处他向往已久的景点旅游。

旅游景点的地图共有 n 处地点,在这些地点之间连有 m 条道路。其中 1 号地点为景区入口,n 号地点为景区出口。我们把一天当中景区开门营业的时间记为 0 时刻,则从 0 时刻起,每间隔 k 单位时间便有一辆旅游巴士到达景区入口,同时有一辆旅游巴士从景区出口驶离景区。

所有道路均只能单向通行。对于每条道路,游客步行通过的用时均为恰好 1 单位时间。

小 Z 希望乘坐旅游巴士到达景区入口,并沿着自己选择的任意路径走到景区出口,再乘坐旅游巴士离开,这意味着他到达和离开景区的时间都必须是 k 的非负整数倍。由于节假日客流众多,小 Z 在旅游巴士离开景区前只想一直沿着景区道路移动,而不想在任何地点(包括景区入口和出口)或者道路上停留。

出发前,小 Z 忽然得知:景区采取了限制客流的方法,对于每条道路均设置了一个 "开放时间"ai ,游客只有不早于 ai 时刻才能通过这条道路。

请帮助小 Z 设计一个旅游方案,使得他乘坐旅游巴士离开景区的时间尽量地早。

输入格式

输入的第一行包含 3 个正整数 n,m,k,表示旅游景点的地点数、道路数,以及旅游巴士的发车间隔。

输入的接下来 m 行,每行包含 3 个非负整数 ui ,vi,ai ,表示第 i 条道路从地点 ui 出发,到达地点 vi,道路的"开放时间"为 ai。

输出格式

输出一行,仅包含一个整数,表示小 Z 最早乘坐旅游巴士离开景区的时刻。如果不存在符合要求的旅游方案,输出 -1。

输入输出样例

输入 #1

5 5 3

1 2 0

2 5 1

1 3 0

3 4 3

4 5 1

输出 #1

6

说明/提示

【样例 #1 解释】

小 Z 可以在 3 时刻到达景区入口,沿 1→3→4→5 的顺序走到景区出口,并在 6 时刻离开。

优先队列代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int M=101,N=1e4+5;
int n,m,T,
	t[M][N];
bool k[M][N];
vector<pair<int,int>> v[N];//各景点所通道路并开方时间 
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;//优先队列 
int main(){
	//freopen("data.cpp","r",stdin);
	cin>>n>>m>>T;
	for(int i=0;i<m;i++){
		int sx,ex,tx;cin>>sx>>ex>>tx;
		v[sx].push_back({tx,ex});
	}
	memset(t,0x3f3f3f,sizeof(t));//找所经更少时间 
	t[0][1]=0;
	q.push({0,1});
	while(!q.empty()){//宽搜 
		int st=q.top().first,sx=q.top().second;q.pop();//到达该景点的时间 
		if(k[st%T][sx])continue;k[st%T][sx]=1;//这个点从这个景点出发过了 
		for(int i=0;i<v[sx].size();i++){//该景点通往其他景点的道路 
			int et=v[sx][i].first,ex=v[sx][i].second,tx;//该道路通行时间和目的景点 
			if(st>=et)tx=st;//通行后才到,刚好 
			else tx=ceil((et-st)*1.0/T)*T+st;//离通行时间差几趟bus, 那就等开通后再来,就是 
			if(t[(tx+1)%T][ex]>tx+1){//只记是一天中的几点到该景区的最少用时 
				t[(tx+1)%T][ex]=tx+1;
				q.push({tx+1,ex});
			}
			if(k[0][n]){
				break;break;
			} 
		}
	}
	if(k[0][n])cout<<t[0][n];
	else cout<<-1;
	return 0;
}

宽搜

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int M=101,N=1e4+5;
int n,m,T,
	t[M][N];
bool k[M][N];
vector<pair<int,int>> v[N];//各景点所通道路并开方时间 
queue<pair<int,int>> q;//优先队列 
int main(){
	//freopen("data.cpp","r",stdin);
	cin>>n>>m>>T;
	for(int i=0;i<m;i++){
		int sx,ex,tx;cin>>sx>>ex>>tx;
		v[sx].push_back({tx,ex});
	}
	memset(t,0x3f3f3f,sizeof(t));//找所经更少时间 
	t[0][1]=0;
	q.push({0,1});
	while(!q.empty()){//宽搜 
		int st=q.front().first,sx=q.front().second;q.pop();//到达该景点的时间 
		//if(k[st%T][sx])continue;k[st%T][sx]=1;//这个点从这个景点出发过了 
		for(int i=0;i<v[sx].size();i++){//该景点通往其他景点的道路 
			int et=v[sx][i].first,ex=v[sx][i].second,tx;//该道路通行时间和目的景点 
			if(st>=et)tx=st;//通行后才到,刚好 
			else tx=ceil((et-st)*1.0/T)*T+st;//离通行时间差几趟bus, 那就等开通后再来,就是 
			if(t[(tx+1)%T][ex]>tx+1){//只记是一天中的几点到该景区的最少用时 
				t[(tx+1)%T][ex]=tx+1;
				q.push({tx+1,ex});
			}
		}
	}
	if(t[0][n]!=0x3f3f3f)cout<<t[0][n];
	else cout<<-1;
	return 0;
}

非满分,不知哪里有问题。

关于时间归拢

小结

就是宽搜题,从1出发各个景点,直到n景点。

难处理的地方是把到达各个景点的最少时间归拢到bus周期内。如今天到该景点,景点通往别景点的道路已通行,则成行。否则就得明天这时间来才能进(如,一天一趟车)。

所以归拢时间是((放行时间-到达时间)/bus间隔时间)------几个间隔时间,乘以间隔时间+到达时间。

用优先队列,第一次到达n景点的时间就是最少时间。否则得全部遍历。

不归拢到bus周期得话考虑的时间太多,也没必要。

相关推荐
vx_biyesheji00011 天前
Python 全国城市租房洞察系统 Django框架 Requests爬虫 可视化 房子 房源 大数据 大模型 计算机毕业设计源码(建议收藏)✅
爬虫·python·机器学习·django·flask·课程设计·旅游
q_35488851532 天前
计算机毕业设计源码:Python动漫智能推荐与可视化分析系统 Django框架 协同过滤推荐算法 可视化 数据分析 大数据 大模型(建议收藏)✅
python·scrapy·数据分析·django·课程设计·旅游·推荐算法
恒星科通3 天前
旅游景区大功率高清晰应急疏散广播技术方案
安全·旅游·广播·应急广播
北漂的老猿3 天前
漂亮大气的酒店和旅游业务预订网站模板WordPress主题
旅游
漫随流水4 天前
旅游推荐系统(view.py)
前端·数据库·python·旅游
漫随流水4 天前
旅游推荐系统(login.html)
前端·html·旅游
QQ8606600164 天前
Python基于Vue的”黄山旅游网站的设计与实现 django flask pycharm
vue.js·python·旅游
漫随流水4 天前
旅游推荐系统(getEchartsData.py)
python·django·旅游
昨夜见军贴06164 天前
旅游客车环境检测中的AI审核与IACheck:让空气质量报告更规范、更可信
人工智能·旅游
EasyDSS4 天前
RTMP高清推流直播/智能转码/无人机直播EasyDSS破局旅游慢直播痛点
ffmpeg·旅游·视频转码·fmp4·点播技术