題目:
小明的飛機快要趕不上了!
幸好大廳的路上有一些傳送帶。每個傳送帶都有一定的速度,傳送帶之間沒有重疊。
小明自己行走的速度爲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了兩發……