网教 5.传送带


题目:

小明的飞机快要赶不上了!
幸好大厅的路上有一些传送带。每个传送带都有一定的速度,传送带之间没有重叠。
小明自己行走的速度为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位小数。

测试用例:

输入

3
10 1 4 2 2
0 1 1
9 10 1
10 1 4 1000 2
0 1 1
9 10 6
20 1 3 20 5
0 4 5
4 8 4
8 12 3
12 16 2
16 20 1
输出

3.000000
2.300000
3.538095



题解:

为了减少时间消耗,经计算可得出要在速度尽量小的传送带/路上跑,而路又可以看作是速度为0的传送带,如此就可以以传送带的处理方法处理n+1个传送带了


错误代码:

#include<stdio.h>       
#include<string.h>       
int a[1000005] = { 0 }, b[1000005] = { 0 }, v[1000005] = { 0 };

int main()
{
	int k;
	scanf("%d", &k);
	while (k--)
	{
		int x, w, r, T;
		int n;
		scanf("%d%d%d%d%d", &x, &w, &r, &T, &n);
		double t;
		t = T;
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		memset(v, 0, sizeof(v));
		int i, j;
		for (i = 0; i < n; i++)
			scanf("%d%d%d", &a[i], &b[i], &v[i]);
		for (i = 0; i < n; i++)
		for (j = 0; j < n - 1; j++)
		if (v[j]>v[j + 1])
		{
			int m;
			m = v[j];
			v[j] = v[j + 1];
			v[j + 1] = m;
			m = a[j];
			a[j] = a[j + 1];
			a[j + 1] = m;
			m = b[j];
			b[j] = b[j + 1];
			b[j + 1] = m;
		}
		int len = 0;
		for (i = 0; i < n; i++)
			len = len + b[i] - a[i];
		len = x - len;//len是非传送带的长度       
		double ans = 0;
		if (t <= len / r)//在非传送带上一直跑也跑不到头       
		{
			ans = t + 1.0*(len - t*r) / w;
			t = 0;
		}
		else
		{
			t = t - 1.0*len / r;
			ans = ans + 1.0*len / r;
		}
		int index = 0;
		while (index<n)
		{
			//          if (t <= 0)       
			//              break;       
			if ((v[index] + r) * t > b[index] - a[index])//在这个传送带上一直跑能跑到尽头       
			{
				t = t - 1.0*(b[index] - a[index]) / (v[index] + r);
				ans = ans + 1.0*(b[index] - a[index]) / (v[index] + r);
			}
			else
			{
				ans = ans + t;
				//t = 0;//这里一开始写错了,t=0位置放错了       
				ans = ans + 1.0*(b[index] - a[index] - t*(v[index] + r)) / (v[index] + w);
				t = 0;
			}
			index++;
		}
		printf("%.6lf\n", ans);
	}
	return 0;
}

这个代码不是T就是WA,因为使用冒泡排序时间复杂度太高了,然后分享思路(与部分代码)之后有了改进版:

//敢交敢wa
//优化:1.不再是以前的冒泡排序,而是用快排直接排结构体 2.节省空间,用一个s来代替以前的a,b
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct node
{
	double s, v;
}tran[1000005];

int cmp(const void *a, const void *b)
{
	struct node *x = (struct node*)a;
	struct node *y = (struct node*)b;
	return x->v > y->v;
}

int main()
{
	int k;
	scanf("%d", &k);
	while (k--)
	{
		double x, w, r, t;
		int n;
		scanf("%lf%lf%lf%lf%d", &x, &w, &r, &t, &n);
		int i, j;
		double maxe=0;
		for (i = 0; i < n; i++)
		{
			double a, b;
			scanf("%lf%lf%lf", &a, &b, &tran[i].v);
			tran[i].s = b - a;
			maxe = maxe + b - a;
		}
		double len = 0;
		len = x - maxe;//len是非传送带的长度
		tran[n].s = len;
		tran[n].v = 0;//在路上相当于传送带的速度为0
		qsort(tran, n + 1, sizeof(tran[0]), cmp);
		double ans = 0;
		int index = 0;
		while (index<n+1)
		{
//			if (t <= 0)
//				break;
			if ((tran[index].v + r) * t > tran[index].s)//在这个传送带上一直跑能跑到尽头
			{
				t = t - 1.0*(tran[index].s) / (tran[index].v + r);
				ans = ans + 1.0*(tran[index].s) / (tran[index].v + r);
			}
			else
			{
				ans = ans + t;
				ans = ans + 1.0*(tran[index].s - t*(tran[index].v + r)) / (tran[index].v + w);
				t = 0;
			}
			index++;
		}
		printf("%.6lf\n", ans);
	}
	return 0;
}

优化的方法已经写出来了,1.使用结构体以方便快排(同时get带着两个元素快排技能),快排减少时间复杂度 2.用一个s代替前面的a和b,能方便速度为0的传送带的表示,也能减少时间复杂度

然后还有一个问题……数据范围是1e6,在数据范围上竟然还RE了两发……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值