传送带问题

问题描述

小明的飞机快要赶不上了!
幸好大厅的路上有一些传送带。每个传送带都有一定的速度,传送带之间没有重叠。
小明自己行走的速度为w,如果传送带的速度为v的话,在传送带上走的速度就是w+v。
但是小明还是很着急,所以他决定跑一段时间t。他跑的速度是r,那么如果传送带的速度为v的话,在传送带上跑的速度就是r+v。
对于时间t,他不一定要连续跑,可以走走再跑。也不一定非要跑够t。
问小明至少需要多少时间才能到达终点。

输入第一行为用例数T,1<=T<=40。
每一组用例的第一行包含五个整数:
X:为大厅的长度,小明起始位于0,终点是X,1<=X<=1000000
W:为走路的速度
R:为跑步的速度,1<=W<R<=100
t:最多能跑t秒,1<=t<=1000000
n:传送带的个数
接下来的n行,表示n个传送带的详细信息。每行包含三个整数:Bi,Ei,Vi,分别表示传送带的起始位置、终止位置和速度,0<=Bi<Ei<=X,1<=vi<=100。任意两个传送带都不相交。
输出包含一个数字,表示至少需要多少时间。输出四舍五入到6位小数。

测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 3↵
  2. 10 1 4 2 2↵
  3. 0 1 1↵
  4. 9 10 1↵
  5. 10 1 4 1000 2↵
  6. 0 1 1↵
  7. 9 10 6↵
  8. 20 1 3 20 5↵
  9. 0 4 5↵
  10. 4 8 4↵
  11. 8 12 3↵
  12. 12 16 2↵
  13. 16 20 1↵
以文本方式显示
  1. 3.000000↵
  2. 2.300000↵
  3. 3.538095↵
1秒 64M 0

题解思路

大致思路:

    要想使时间最短,尽量在速度小的传送带上跑(可以把没有传送带的地方看做是速度为0的传送带)。然后进行逐次的累计时间即可。

思路证明:

      对于所有的路程来说,速度的范围是在0~100之间的,根据时间公式t=s/v,因为s是一定的,所以就看怎么处理v的问题。如果人是静止的,那么人要走完这段路程所需要的时间就是各个速度的传送带的长度除以各个传送带的速度。那么对于地面来说需要的时间就是正无穷(相当于除以0)。然后下面我们就把跑步的速度(因为随时都可以走,所以这个地方可以先忽略走路的速度)加在上面每个速度段的速度上,看怎么加完之后所用的总时间减少的最多。极端的想法可以有三种:一,优先从速度小的加,即从速度为0的传送带加,这样的话无论跑步的速度为多大,加完之后的时间会从正无穷减小到一个有限的数,时间减小是无穷倍的二,优先从速度大的传送带上加,这样的话,如果传送带的速度比人跑的速度大的话,那么时间减小的量不会超过1倍;三,优先从中间的速度加,这样的话,无论跑步的速度比传送带的速度大还是小最后时间减小的倍数都是一个有限值;对比这三种方法,只有第一种时间的减小量是一个无限值,所以尽量在速度小的传送带上跑是最省时间的。

具体实现方式:

    把各个传送带的长度按速度的大小进行分类存储,把速度相同的传送带合并在一起(输入传送带的三个信息,qidian,zhondian,speed,l令sp[0]=总路程,读入的时候可以这样读入{sp[speed]+=zhongdian-qidian;sp[0]-=zhongdian-qidian;}),然后根据能跑步的时间进行比较,讨论,累和。对于每一截传送带首先要进行判断,判断可以跑步的时间是否可以将这一节传送带跑完(判断的方法就是用跑步和传送带本身的速度之和乘以可以跑步的时间),如果可以跑完那这一节的时间久可以直接用这一节的长度除以传送带和跑步的速度之和,然后可以跑步的时间再减去跑这一节所用的时间({time+=sp[j]/(r+j);t-=sp[j]/(r+j);})。如果跑不完的话,就把这一节的长度分为两段,一段时在传送带上跑,一段是在传送带上走,分别计算时间,计算完了之后把能跑步的时间清为0。{time+=(sp[j]-t*(r+j))/(j+w)+t;t=0;}这样通过一次循环就可以处理掉所有的情况,但是在处理的时候要注意:1,因为最后的结果是保留6位小数的,所以在计算时间的时候可以有两种处理方法,一是使用强制转换,计算的时候转换为实型的数;另一种方法就是在定义累计传送带速度的数组时定义为double型的数组。2,在每次大循环的时候注意要把存储长度的数组清0.

代码实现

#include<stdio.h>
int main()
{
	int n,T,w,r;
	double sp[101];
	double time,x,t;
	int temp1,temp2,temp3;
	int i,j;
	
	scanf("%d",&T);
	for(i=0;i<T;i++)
	{
		time=0;
		for(j=0;j<101;j++)
		{
			sp[j]=0;
		}
		scanf("%lf%d%d%lf%d",&x,&w,&r,&t,&n);
		sp[0]=x;
		for(j=0;j<n;j++)
		{
			scanf("%d%d%d",&temp1,&temp2,&temp3);
			sp[temp3]+=temp2-temp1;
			sp[0]-=temp2-temp1;
		}
		for(j=0;j<101;j++)
		{
			if(sp[j]!=0&&t*(r+j)>sp[j])
			{
				time+=sp[j]/(r+j);
				t-=sp[j]/(r+j);
			}
			else if(sp[j]!=0)
			{
				time+=(sp[j]-t*(r+j))/(j+w)+t;
				t=0;
			}
			else
			;
		}
		printf("%.6lf\n",time);
	
		
	}
	return 0; 
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值