UVA1336 修缮长城 Fixing the Great Wall

Description

传送门


Solution

因为只要经过就会修所以最优的修缮策略是从起点开始往左或往右修一段区间,所以考虑反向区间\(dp\)

\(dp_{i, j}\)表示修缮完区间\([i, j]\)后的时间内再修其它区间产生的花费。

那么转移时不需要考虑区间\([i, j]\),只需要考虑除了区间\([i, j]\)以外的点。

发现修缮区间\([i, j]\)时花费的时间会对以后要修复的点产生影响,具体的,还没有修复的那些点对答案的贡献会加上从区间\([i, j]\)转移到下个区间的时间乘单位时间的代价。

所以只需计算区间和区间转移时花费的时间。

注意到修缮完一个区间后一定是在区间的左/右端点,所以可以设\(dp_{i, j, 0/1}\)表示当前修缮到区间\([i, j]\)位于左/右端点,以后的时间内修缮完其他的点的代价。

\(s_i\)表示区间\([1, i]\)内的\(\Delta\)的和,\(len_{i, j}\)表示点\(i\)到点\(j\)的距离。很容易的列出\(dp\)式子:

\[cost = s_n - (s_j - s_{i - 1}) \]

\[dp_{i, j, 0} \leftarrow dp_{i - 1, j, 0} + \frac{cost \times len_{i - 1, i}}{v} \]

\[dp_{i, j, 0} \leftarrow dp_{i, j + 1, 1} + \frac{cost \times len_{i, j + 1}}{v} \]

\[dp_{i, j, 1} \leftarrow dp_{i - 1, j, 0} + \frac{cost \times len_{i - 1, j}}{v} \]

\[dp_{i, j, 1} \leftarrow dp_{i, j + 1, 1} + \frac{cost \times len_{j, j + 1}}{v} \]


Code

/*
    _______                       ________                        _______
   / _____ \                     / ______ \                      / _____ \
  / /     \_\  _     __     _   / /      \ \   _     __     _   / /     \_\
 | |          | |   |  |   | | | |        | | | |   |  |   | | | |
 | |          | |   |  |   | | | |     __ | | | |   |  |   | | | |
 | |       __ \  \  |  |  /  / | |     \ \| | \  \  |  |  /  / | |       __
  \ \_____/ /  \  \/ /\ \/  /   \ \_____\  /   \  \/ /\ \/  /   \ \_____/ /
   \_______/    \___/  \___/     \______/\__\   \___/  \___/     \_______/
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

#define db double

const int N = 1000;

int n, x;

db dp[N + 50][N + 50][2], sum[N + 50], ans, v;

struct Point {
	int pos; db zhi, delta;
} point[N + 50];

bool Cmp(Point a, Point b) {
	return a.pos < b.pos;
}

int main() {
	while (scanf("%d%lf%d", &n, &v, &x) == 3) {
		if (!n && !v && !x) return 0;
		for (int i = 1; i <= n; i++) 
			scanf("%d%lf%lf", &point[i].pos, &point[i].zhi, &point[i].delta);
		point[++n].pos = x; point[n].zhi = point[n].delta = 0.0;
		sort(point + 1, point + n + 1, Cmp);
		int pos;
		for (int i = 1; i <= n; i++) 
			if (point[i].pos == x && point[i].delta == 0.0 && point[i].zhi == 0.0) {
				pos = i;
				break;
			}
		ans = 0;
		for (int i = 1; i <= n; i++) 
			sum[i] = sum[i - 1] + point[i].delta,
			ans += point[i].zhi;
		for (int i = 1; i <= n; i++) 
			for (int j = 1; j <= n; j++)
				dp[i][j][0] = dp[i][j][1] = 1e9;
		dp[1][n][0] = dp[1][n][1] = 0.0; 
		for (int l = n - 1; l >= 1; l--)	
			for (int i = 1; i + l - 1 <= n; i++) {
				int j = i + l - 1; db cost = sum[n] - sum[j] + sum[i - 1];
				if (i - 1 >= 1) dp[i][j][0] = min(dp[i][j][0], dp[i - 1][j][0] + cost * (db)(point[i].pos - point[i - 1].pos) / v);
				if (j + 1 <= n) dp[i][j][0] = min(dp[i][j][0], dp[i][j + 1][1] + cost * (db)(point[j + 1].pos - point[i].pos) / v);
				if (j + 1 <= n) dp[i][j][1] = min(dp[i][j][1], dp[i][j + 1][1] + cost * (db)(point[j + 1].pos - point[j].pos) / v);
				if (i - 1 >= 1) dp[i][j][1] = min(dp[i][j][1], dp[i - 1][j][0] + cost * (db)(point[j].pos - point[i - 1].pos) / v);
			}
		printf("%d\n", (int)floor(ans + min(dp[pos][pos][0], dp[pos][pos][1])));
	}
	return 0;
}
posted @ 2020-11-17 09:03  Tian-Xing  阅读(112)  评论(0编辑  收藏  举报