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