[BZOJ 4244] 邮戳拉力赛

BZOJ传送门

Description

IOI铁路是由 N + 2 N+2 N+2个站点构成的直线线路。这条线路的车站从某一端的车站开始顺次标号为 0... N + 1 0...N+1 0...N+1

这条路线上行驶的电车分为上行电车和下行电车两种,上行电车沿编号增大方向行驶,下行电车沿编号减小方向行驶。乘坐这两种电车的话,移动1站的距离需要 T T T秒。换句话说,乘坐上行电车从车站i走到车站 i + 1 i+1 i+1需要 T T T秒,称作下行电车从车站 i i i走到车站 i − 1 i-1 i1也需要 T T T秒。你不能在 0 0 0号车站乘坐下行电车,或在 N + 1 N+1 N+1号车站乘坐上行电车。由于电车发车的频率非常高,你可以无视等待电车消耗的时间。

每个车站设有上行电车的站台和下行电车的站台,连接两个站台的道路上设有邮戳台。

现在,IOI铁路召开了邮戳拉力赛。在拉力赛中,选手需要从 0 0 0号车站的上行电车站台出发,在 1... N 1...N 1...N号车站各盖一枚邮戳,最终到达 N + 1 N+1 N+1号车站的上行电车站台即可完成。

为了在每个车站盖上邮戳,必须从电车上下来,步行走到车站通路上的邮戳台。在 i i i号车站的上行电车站台、邮戳台、下行电车站台之间移动所消耗的时间如下所示:

从车站 i i i的上行电车站台到邮戳台的时间为 U i U_i Ui

从车站 i i i的邮戳台到上行电车站台的时间为 V i V_i Vi

从车站 i i i的下行电车站台到邮戳台的时间为 D i D_i Di

从车站 i i i的邮戳台到下行电车站台的时间为 E i E_i Ei

邮戳拉力赛的选手只能访问 0 0 0号车站与 N + 1 N+1 N+1号车站各一次。 1... N 1...N 1...N号车站都可以访问任意多次。

现在给出有邮戳台的车站个数、乘坐电车移动一站的时间、在每个车站的上行电车站台、邮戳台、下行电车站台之间移动所消耗的时间,请你求出完成邮戳拉力赛的最短时间。

这个时间包括从 0 0 0号车站出发,按下 N N N个邮戳后到达 N + 1 N+1 N+1号车站的时间。无视等车的时间和按邮戳的时间。

Input

第一行两个空格分隔的整数 N N N T T T,表示有 N + 2 N+2 N+2个车站,电车行驶一站的距离需要 T T T

接下来 N N N行,第 i i i行有四个空格分隔的整数 U i , V i , D i , E i U_i,V_i,D_i,E_i Ui,Vi,Di,Ei,分别表示:

从车站 i i i的上行电车站台到邮戳台的时间为 U i U_i Ui

从车站 i i i的邮戳台到上行电车站台的时间为 V i V_i Vi

从车站 i i i的下行电车站台到邮戳台的时间为 D i D_i Di

从车站 i i i的邮戳台到下行电车站台的时间为 E i E_i Ei

Output

输出一行一个整数,表示完成邮戳拉力赛的最短时间。

Sample Input

4 1
1 1 1 1
1 9 9 1
9 9 1 1
1 9 9 1

Sample Output

23

HINT

从车站 0 0 0出发,按照 2 − 1 − 4 − 3 − 1 − 5 2-1-4-3-1-5 214315的顺序访问车站可以达到最短时间。

1 ≤ N ≤ 3000 1\le N\le 3000 1N3000

1 ≤ T ≤ 1 0 5 1\le T\le 10^5 1T105

1 ≤ U i ≤ 1 0 5 ( 1 ≤ i ≤ N ) 1\le Ui\le 10^5(1\le i\le N) 1Ui105(1iN)

1 ≤ V i ≤ 1 0 5 ( 1 ≤ i ≤ N ) 1\le Vi\le 10^5(1\le i\le N) 1Vi105(1iN)

1 ≤ D i ≤ 1 0 5 ( 1 ≤ i ≤ N ) 1\le Di\le 10^5(1\le i\le N) 1Di105(1iN)

1 ≤ E i ≤ 1 0 5 ( 1 ≤ i ≤ N ) 1\le Ei\le 10^5(1\le i\le N) 1Ei105(1iN)

解题分析

D P DP DP神题, 自己并不会搞出这个状态。

因为如果我们从上行线转到了下行线, 一定是要从前面的一个位置再回到上行线。 那么实际上整个图是由很多环构成的。

d p [ i ] [ j ] dp[i][j] dp[i][j]表示处理到第 i i i个位置, 从下行到上行的路径经过次数比上行到下行的路径经过次数多 j j j次(也就是我们还需要向下走 j j j次。 那么就可以科学转移了。

注意如果要从下面得到邮戳, j j j需要 > 0 >0 >0, 即我们还有从下面经过这个点的可能。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 3005
#define ll long long
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
ll dp[MX][MX];
int n, T;
int main(void)
{
	int u, v, d, e;
	in(n), in(T);
	std::memset(dp, 63, sizeof(dp));
	dp[0][0] = 0;
	R int i, j;
	for (i = 1; i <= n; ++i)
	{
		in(u), in(v), in(d), in(e);
		for (j = 1; j <= n; ++j) dp[i - 1][j] += j * T * 2;
		for (j = 1; j <= n; ++j) dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + d + v);
		for (j = 0; j <  n; ++j) dp[i][j] = min(dp[i][j], dp[i - 1][j + 1] + u + e);
		for (j = 0; j <= n; ++j) dp[i][j] = min(dp[i][j], dp[i - 1][j] + u + v);
		for (j = 1; j <= n; ++j) dp[i][j] = min(dp[i][j], dp[i - 1][j] + e + d);
		for (j = 1; j <= n; ++j) dp[i][j] = min(dp[i][j], dp[i][j - 1] + d + v);
		for (j = i - 1; ~j; --j) dp[i][j] = min(dp[i][j], dp[i][j + 1] + u + e);
	}
	printf("%lld", dp[n][0] + 1ll * (n + 1) * T);
}

你可能感兴趣的:(动态规划)