POJ1661 Help Jimmy

2017年8月14日

Jimmy 落到一个平台后,要么向左,要么向右,对于任意一个平台都是这样。如果知道了 Jimmy 落到某一平台后的位置,向左或者向右到另外一个平台,这样就产生了两个子问题,这两个子问题与原问题是一样的。所以我们只需求从平台的左、右端点到地面的最短时间。

dp[i][0] 表示第 i 个平台左端点到地面的最短时间,dp[i][1] 表示第 i 个平台右端点到地面的最短时间。

将所有平台按高度从低到高的顺序排列。对于第 i 个平台的左端点,找到的第一个比 i 平台要低,且左端点在这个平台上的话,就有 dp[i][0] = min(e[i].l - e[j].l + dp[j][0], e[j].r - e[i].l + dp[j][1]) + e[i].h - e[j].h。右端也类似。
如果没有找到哪个平台比 i 平台要低,就看看能不能直接到地面,能的话dp[i][0]就是等于平台到地面的距离。

链接:http://poj.org/problem?id=1661

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1005;
const int M = 20005;
struct edge {
  int l, r, h;
  bool operator < (const edge &a) const {
    return h < a.h;
  }
} e[N];
int dp[N][2];
int main()
{
  int t;
  scanf("%d", &t);
  while (t--) {
    int n, x, y, mx;
    scanf("%d %d %d %d", &n, &x, &y, &mx);
    for (int i = 1; i <= n; i++) {
      scanf("%d %d %d", &e[i].l, &e[i].r, &e[i].h);
    }
    sort(e + 1, e + n + 1);
    memset(dp, INF, sizeof(dp));
    for (int i = 1; i <= n; i++) {
      bool flag_l = 0, flag_r = 0;
      for (int j = i - 1; j >= 1; j--) {
        if (e[i].h - e[j].h > mx)
          continue;
        if (e[j].l <= e[i].l && e[i].l <= e[j].r && !flag_l) {
          flag_l = 1;
          dp[i][0] = min(e[i].l - e[j].l + dp[j][0], e[j].r - e[i].l + dp[j][1]) + e[i].h - e[j].h;
        }
        if (e[j].l <= e[i].r && e[i].r <= e[j].r && !flag_r) {
          flag_r = 1;
          dp[i][1] = min(e[i].r - e[j].l + dp[j][0], e[j].r - e[i].r + dp[j][1]) + e[i].h - e[j].h;
        }
        if (flag_l && flag_r)
          break;
      }
      if (!flag_l && e[i].h <= mx) {
        dp[i][0] = e[i].h;
      }
      if (!flag_r && e[i].h <= mx) {
        dp[i][1] = e[i].h;
      }
    }
    int m = n;
    while (m > 0) {
      if (e[m].l <= x && x <= e[m].r && y >= e[m].h)
        break;
      m--;
    }
    if (m == 0) {
      printf("%d\n", y);
    } else {
      printf("%d\n", min(x - e[m].l + dp[m][0], e[m].r - x + dp[m][1]) + y - e[m].h);
    }
  }
  return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注