P7655 [BalticOI 1996 Day 2] A FAST JOURNEY

文章描述了一个编程问题,涉及寻找从城市A到城市B的最短路径,考虑了奇偶日交通规则和每天最多12小时的旅行限制。要求在满足条件的情况下找到最优的路线,包括可能的停留天数。
摘要由CSDN通过智能技术生成

题目描述

一侧的交通道路连接了许多城市。城市从 11 到 n 编号,其中 n 是城市的数量。在奇数天,车辆按照交通指示的方向行驶,在偶数天,则沿相反的方向行驶。两个城市之间的道路长度用一个整数值来衡量——从一个城市到另一个城市的旅程的持续时间(以小时为单位),它与方向无关。

编写一个程序来查找从城市 A 到城市 B 的路线,以便尽可能快地到达城市 B。

旅程的第一天是奇数天。一天之内的旅程不能超过十二个小时。晚上必须在一个城市度过。行程可能会在第二天继续。

输入格式

第一行包含两个整数为 A 和 B 城市的编号,第二行包含两个整数为城市总数和道路总数 k。剩下的 k 行中有每条道路的信息,每行包含三个整数——道路连接的两个城市的编号以及以小时表示的城市之间旅程的持续时间。道路的方向是从第一城到第二城。

输出格式

每条中间路径输出一行。每行应该有四个整数——出发城市标号、到达城市编号、日期和道路长度。

输入输出样例

输入 #1

1 3
6 7
1 2 9
1 6 2
1 5 10
5 4 1
4 6 2
4 3 4
2 3 5

输出 #1

1 5 1 10
5 4 1 1
4 3 3 4

说明/提示

数据规模与约定

对于 100% 的数据,1<n≤100,1≤k≤1000。

样例说明
分值说明

本题分值按 BOI 原题设置,满分 35 。

题目说明

来源于 Baltic Olympiad in Informatics 1996 的 Day 2:A FAST JOURNEY
由 @求学的企鹅(封禁用户) 翻译整理。

题目难度

普及/提高-

参考思路

题意可直接转化为:

每天共有 12 个小时,每走一条路会消耗一定小时,用尽后或大于剩余时间当天将不能再走。

以及,奇数天走路的正方向,偶数天走路的反方向,求从起点到终点所用最短时间(优先天数,天数相同比较当天剩余时间)时的路径。

样例为:

第一天:1→5→4。

第二天:留在 4。

第三天:4→3。

分析

如果想要保证走的时间最短,就应该使用最短路,我们从一个点出发到一个点时,以天数为第一关键字,当前天数所剩时间为第二关键字进行优先队列的标准进行 Dij,如果当前天的时间加上走这条的时间小于等于 12 则可以转移,如果大于则无法转移。

但是这并不能覆盖样例的等候情况,因此我们需要判断是否能够在一个地点等一天,所以我们直接在判断之后进行一次下一天的过渡,在转移过程中记录相关信息,最后到终点时直接输出即可。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-f;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}
struct node{
	int da,ti,np;
	friend bool operator < (node x,node y)
	{
		if(x.da==y.da) return x.ti>y.ti;
		return x.da>y.da;
	}
};//天数,天数相同比较时间
priority_queue<node> q;
int hpla[110],st,to[2010],nxt[2010],head[2010],val[2010],fl[2010],cnt,vis[110][2][20],pre[110],hpt[110],hpti[110];
int ansp[110],ansx[110],anst[110],ansti[110];
void addedge(int x,int y,int z,int ff)
{
	to[++cnt]=y;
	nxt[cnt]=head[x];
	head[x]=cnt;
	val[cnt]=z;
	fl[cnt]=ff;//正图还是反图
}
void out(int x,int &nc)
{
	ansp[nc]=pre[x];
	ansx[nc]=x;
	anst[nc]=hpt[x];
	ansti[nc]=hpti[x];//取出路径
	nc++;
	if(pre[x]==st) return;
	out(pre[x],nc);
}
int main()
{
	int x,y,z;st=read();
	int ed=read(),n=read(),m=read();
	memset(hpt,0x3f,sizeof(hpt));
	memset(hpti,0x3f,sizeof(hpti));
	for(int i=1;i<=m;i++)
	{
		x=read(),y=read(),z=read();
		addedge(x,y,z,1);
		addedge(y,x,z,0);
	}
	vis[st][1][0]=1;
	q.push((node){1,0,st});
	while(!q.empty())
	{
		node nq=q.top();
		q.pop();
		if(nq.np==ed)//到了直接输出
		{
			int cc=0;
			out(nq.np,cc);
			for(int i=cc-1;i>=0;i--)
			{
				cout<<ansp[i]<<" "<<ansx[i]<<" "<<anst[i]<<" "<<ansti[i]<<endl;
			}
			return 0;
		}
		x=nq.np;
		int d=nq.da,tt=nq.ti;
		for(int i=head[x];i;i=nxt[i])
		{
			int ft=to[i],ro=val[i];
			if(tt+ro<=12)//如果一天还未结束
			{
				if(!vis[ft][d%2][tt+ro]&&d%2==fl[i])//当前时间没有走过
				{
					if(d<hpt[ft]||(d==hpt[ft]&&tt+ro<hpla[ft]))//剩余时间更优
					{
						pre[ft]=x;
						hpt[ft]=d;
						hpti[ft]=ro;
						hpla[ft]=ro+tt;
					}
					vis[ft][d%2][tt+ro]=1;
					q.push((node){d,tt+ro,ft});
				}
			}
		}
		if(!vis[x][(d+1)%2][0])//注意!可以选择在某个地方停留一天
		{
			q.push((node){d+1,0,x});
		}
	}
}

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值