[Luogu P4469] [BZOJ 1075] [SCOI2007]最優駕車

洛谷傳送門

BZOJ傳送門

題目描述

nn條南北方向的雙向街道和nn條東西方向的雙向街道縱橫交錯。相鄰街道(不管是哪個走向)的距離均爲LL英里。西南角交叉口的座標爲(1,1)(1,1),東北角爲(n,n)(n,n)。在所有交叉口均可任意改變行駛方向。每條街道有它自己的最高速度限制,該限制對整條街道有效(不管行駛方向如何)。

你的任務是從交叉口(xs,ys)(x_s,y_s)開車行駛到(xt,yt)(x_t,y_t),要求只能在交叉口處改變速度,行駛過程中不得違反所在街道的速度限制,只能沿着路程最短的線路行駛,並且行駛時間在給定的閉區間[t1,t2][t_1,t_2]內。車速以“每小時英里數”爲單位,它必須是55的正整數倍。若車速爲vv,則每加侖汽油能行駛的英里數爲800.03v280-0.03v^2

輸入輸出格式

輸入格式:

輸入第一行爲兩個整數n,Ln, L
第二行包含nn個正整數,從南到北描述nn條東西走向的街道的速度限制。
第三行包含nn個正整數,從西到東描述nn條南北走向的街道的速度限制。
第四行包含六個正整數xs,ys,xt,yt,t1,t2x_s, y_s, x_t, y_t, t_1, t_2

輸出格式:

如果無解,輸出No

否則輸出兩行,分別描述最早到達的方案(若有多種方案,選擇其中最省油的)和最省油的方案(如果有多種方案,選擇其中最早到達的)。每種方案用兩個數表示,第一個數表示到達時刻(單位:分鐘,向上取整);第二個數表示耗油量(單位:加侖,四捨五入保留兩位小數)。

輸入輸出樣例

輸入樣例#1:

6 20
30 40 50 50 50 50
50 50 50 50 50 40
1 1 6 6 300 320

輸出樣例#1:

300 6.25
318 5.60

輸入樣例#2:

8 2
10 20 20 30 10 20 10 10
10 20 20 30 10 20 10 20
6 8 2 4 10 39

輸出樣例#2:

No

說明

樣例11的最快路線爲以4040英里/小時爲速度勻速前進,路程爲200200英里,因此時間爲55小時,每加侖汽油可以行駛800.034040=3280-0.03*40*40=32英里,因此耗油量爲200/32=6.25200/32=6.25加侖。

最省油路線是先以4040英里/小時行駛120120英里,然後以3535英里/小時行駛8080英里,耗油量爲120/32+80/(800.033535)=5.60120/32+80/(80-0.03*35*35)=5.60加侖。下圖的路線可以同時滿足兩種方案(其中第二種方案需要在(6,2)(6,2)處改變速度)。

img

20%的數據滿足:n4n\le 4

50%的數據滿足:n8n\le 8

100%的數據滿足:1n10,1l20,0t1t210001\le n\le 10, 1\le l\le 20, 0\le t_1\le t_2\le 1000. 速度限制不超過5050

解題分析

思路很妙妙的DPDP

很容易看出, 如果我們設dp[i][j][k]dp[i][j][k]爲在xx方向走了ii步, 在yy方向走了jj步, 油量或時間用了kk的最優時間/油量, 都可以轉移,問題在於kk是一個實數, 無法記錄這一維狀態。

考慮轉化一下時間: 我們要求先把速度÷5\div5, 使速度變爲1101\to10的正整數, 最後把時間÷5\div 5就可以轉化回來了。 然後我們想記錄的時間實際上是(1v1+1vn+...+1vn)L(\frac{1}{v_1}+\frac{1}{v_n}+...+\frac{1}{v_n})L, 先統一乘一個LCM(1,2,3,..,10)LCM(1,2,3,..,10) ,就可以轉化爲一個整數的狀態, 最後再除回來就好了。

注意題目問的是分鐘, 給的是小時, 乘上60。

總複雜度O(n3LCMMaxspeed)O(n^3LCM*Maxspeed)

代碼如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define EPS 1e-8
#define INF 1e20
#define gc getchar()
#define ll long long
#define db double
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
const int LCM = 2520;
const int UP = 2 * 10 * LCM;
int n, L, t1, t2;
int dx, dy, sx, sy, tx, ty, delx, dely;
int limx[15], limy[15], tcost[15];
db dp[11][11][UP + 1];
IN db calc(R int v) {return 80 - 0.03 * v * v;}
int main(void)
{
	R int i, j, k, v, cx, cy, nxx, nxy;
	scanf("%d%d", &n, &L);
	for (i = 0; i < n; ++i) scanf("%d", &limx[i]);//lr
	for (i = 0; i < n; ++i) scanf("%d", &limy[i]);//ud
	scanf("%d%d%d%d%d%d", &sx, &sy, &tx, &ty, &t1, &t2);
	sx--, sy--, tx--, ty--;
	delx = abs(tx - sx), dely = abs(ty - sy);
	dx = tx - sx < 0 ? -1 : 1, dy = ty - sy < 0 ? -1 : 1;
	for (R int i = 1; i <= 10; ++i) tcost[i] = LCM / i;
	for (i = 0; i <= delx; ++i)
	for (j = 0; j <= dely; ++j)
	for (k = 0; k <= UP; ++k)
	dp[i][j][k] = INF;
	dp[0][0][0] = 0;
	for (i = 0; i <= delx; ++i)
	for (j = 0; j <= dely; ++j)
	for (k = 0; k <= UP; ++k) if (dp[i][j][k] < INF)
	{
		cx = i + 1, cy = j;
		if (cx <= delx)
		{
			nxx = sx + cx * dx, nxy = sy + cy * dy;
			for (v = 1; v * 5 <= limx[nxy] && tcost[v] + k <= UP; ++v)
			dp[cx][cy][tcost[v] + k] = min(dp[cx][cy][tcost[v] + k], dp[i][j][k] + 1.0 * L / calc(5 * v));
		}
		cx = i, cy = j + 1;
		if (cy <= dely)
		{
			nxx = sx + cx * dx, nxy = sy + cy * dy;
			for (v = 1; v * 5 <= limy[nxx] && tcost[v] + k <= UP; ++v)
			dp[cx][cy][tcost[v] + k] = min(dp[cx][cy][tcost[v] + k], dp[i][j][k] + 1.0 * L / calc(5 * v));
		}
	}
	int mntim = -1, mnoil = -1;
	for (i = 0; i <= UP; ++i) if (dp[delx][dely][i] != INF)
	{
		db tim = 1.0 * i * L * 12 / LCM;
		if (tim >= t1 && tim <= t2)
		{
			if (mntim == -1) mntim = i;
			if (mnoil == -1) mnoil = i;
			else if (dp[delx][dely][i] < dp[delx][dely][mnoil]) mnoil = i;
		}
	}
	if (mntim == -1) return puts("No"), 0;
	printf("%d %.2lf\n", (int)std::ceil(1.0 * mntim * L * 12 / LCM), dp[delx][dely][mntim]);
	printf("%d %.2lf\n", (int)std::ceil(1.0 * mnoil * L * 12 / LCM), dp[delx][dely][mnoil]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章