1. 程式人生 > >汽車加油問題(動態規劃)

汽車加油問題(動態規劃)

問題描述

一個美國旅行代理商經常被要求去估計開車從一個城市旅行至另一個城市的最小費用。他有一個在通常路線上的大多數加油站的列表。列表包括了所有加油站的位置及當前每加侖汽油的價格。

為了簡化估計費用的過程,代理商使用了以下的簡化汽車駕駛員行為的規則:

● 除非汽車無法用油箱裡的汽油達到下一個加油站(如果有的話)或目的地,在油箱裡還有不少於最大容量一半的汽油時,駕駛員從不在加油站停下來。

● 在每一個停下的加油站,駕駛員總是將油加滿。

● 在一個加油站停下之後,駕駛員將為旅程在快餐和糖果上花去2.00元。

● 在駛向加油站或目的地時,駕駛員不需要超過必須量的汽油。不需要“安全餘量”。

● 駕駛員開始旅行時油箱總是滿的。

● 每個加油站付款時四捨五入到分(1元等於100分)。

你必須寫一個程式以估計駕駛員在旅程上至少要為汽油和食品付多少錢。

輸入格式

開始的2行給出了出發地和目的地的資訊。

資料的後繼若干行代表了路線上的加油站,每個加油站用一行表示。下面是輸入資料中資料項的精確格式及其含義。

第一行:一個實數——從出發地到目的地的距離(英里)。

第二行:三個實數及一個整數。

● 第一個實數是汽車油箱的最大的容量(加侖)。

● 第二個實數是汽車每加侖汽油可以行駛的英里數。

● 第三個實數是汽車在出發地城市加滿油箱的費用(單位:元)。

● 整數(小於51)是路線上加油站的數目。

    接下來的每一行:兩個實數。

● 第一個實數是從出發地到加油站的距離(單位:英里)。

● 第二個實數是該加油站出售的汽油每加侖的價格(單位:分)。

資料項中的所有資料都是正的。一條路線上的加油站根據其到出發地的距離遞增排列。路線上不存在這樣的加油站,它到出發點的距離大於從出發點到目的地的距離。每條路線上的加油站都被適當的安排以使得任何汽車都能從出發地開到目的地。

輸出格式

僅一個實數(保留兩位小數),表示最小的花費(單位:元)。

樣例輸入

475.6

11.9 27.4 14.98 6

102.0 99.9

220.0 132.9

256.3 147.9

275.0 102.9

277.6 112.9

381.8 100.9

樣例輸出

27.31

這道題雖然很簡單,但是那個條件想起來還是比較麻煩。

一開始WA80,是因為沒有理解題意。

我是把終點當做了一個加油站,其實不能這樣,因為這句話:

● 除非汽車無法用油箱裡的汽油達到下一個加油站(如果有的話)或目的地,在油箱裡還有不少於最大容量一半的汽油時,駕駛員從不在加油站停下來。

但是是可以有不少於容量一半的汽油到達終點。

所以應該列舉距離不超過油量限制的最後一個點,找到最小解。

#include <cstdio>
#define min(a,b) ((a)<(b)?(a):(b))

const double eps = 1e-8;
const double inf = 1e19;
double d[60];
double v[60];
double D,S,M,init;
long n;
double f[60];

int main()
{
	freopen("oil.in","r",stdin);
	freopen("oil.out","w",stdout);
	scanf("%lf%lf%lf%lf%ld",&D,&S,&M,&init,&n);
	for (long i=1;i<n+1;i++)
	{
		scanf("%lf%lf",d+i,v+i);
		v[i] /= 100.0;
	}
	for (long i=1;i<n+1;i++)
		f[i] = inf; 
	f[0] = init;
	for (long i=1;i<n+1;i++)
	{
		for (long j=i-1;j>=0;j--)
		{
			if (d[i]-d[j] > M*S+eps)
				break;
			if (d[i]-d[j] > M*S/2+eps)
			{
				f[i] = min(f[i],f[j]+v[i]*((d[i]-d[j])/M)+2);
			}
		}
	}
	double ans = 1e19;
	for (long i=n;i>=0;i--)
	{
		if (D - d[i] > M*S+eps)
			break;
		ans = min(ans,f[i]);
	}
	printf("%.2lf",ans);
	return 0;
}