網教 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了兩發……

發佈了25 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章