很棒的题,一开始用搜索做一直不对,后来才发现是DP。
将一开始的位置和地面都看作是一个平台。
先将每个平台按照高度从小到大排序。
dp[i][[0]和dp[i][1]分别表示从第i个平台从左端和从右端到地面的最小时间,那么dp[i]就取决于高度低于i平台的可到达的第一块平台k,dp[i][0] = 高度差 + min(dp[k][0]+i左端到k左端的距离, dp[k][1] + i左端到k右端的距离);
同理, dp[i][1] = 高度差 + min(dp[k][0]+i右端到k左端的距离, dp[k][1] + i右端到k右端的距离);
再考虑一下特殊情况,自低向上dp一下即可。
//POJ1661
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1000 + 10;
const int INF = 20000;
struct plat {
int x1, x2, h;
};
int n, MAX;
plat p[maxn];
int dp[maxn][2];
bool comp(const plat& a, const plat& b) {
return a.h < b.h;
}
void leftmin(int i) {
int k = i - 1;
while (k > 0 && p[i].h - p[k].h <= MAX) {
if (p[k].x1 <= p[i].x1 && p[i].x1 <= p[k].x2) {
dp[i][0] = p[i].h - p[k].h + min(p[i].x1 - p[k].x1 + dp[k][0]
, p[k].x2 - p[i].x1 + dp[k][1]);
return;
} else {
k--;
}
}
if (p[i].h - p[k].h > MAX) {
dp[i][0] = INF;
} else {
dp[i][0] = p[i].h;
}
}
void rightmin(int i) {
int k = i - 1;
while (k > 0 && p[i].h - p[k].h <= MAX) {
if (p[k].x1 <= p[i].x2 && p[i].x2 <= p[k].x2) {
dp[i][1] = p[i].h - p[k].h + min(p[i].x2 - p[k].x1 + dp[k][0]
, p[k].x2 - p[i].x2 + dp[k][1]);
return;
} else {
k--;
}
}
if (p[i].h - p[k].h > MAX) {
dp[i][1] = INF;
} else {
dp[i][1] = p[i].h;
}
}
int main(int argc, char const *argv[]) {
int t;
scanf("%d", &t);
while (t--) {
int x, y;
scanf("%d%d%d%d", &n, &x, &y, &MAX);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &p[i].x1, &p[i].x2, &p[i].h);
}
p[0].x1 = x;
p[0].x2 = x;
p[0].h = y;
p[n+1].x1 = -20000;
p[n+1].x2 = 20000;
p[n+1].h = 0;
n += 2;
sort(p, p + n, comp);
for (int i = 0; i < n; i++) {
leftmin(i);
rightmin(i);
}
printf("%d\n", min(dp[n-1][0], dp[n-1][1]));
}
return 0;
}