poj 1661:帮助 Jimmy

总时间限制:
1000ms
内存限制:
65536kB

描述
“Help Jimmy” 是在下图所示的场景上完成的游戏。
这里写图片描述
场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。

Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。

设计一个程序,计算Jimmy到底地面时可能的最早时间。
输入
第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是四个整数N,X,Y,MAX,用空格分隔。N是平台的数目(不包括地面),X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。接下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1 <= N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1..N)。所有坐标的单位都是米。

Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。
输出
对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。
样例输入

1
3 8 17 20
0 10 8
0 10 13
4 14 3

样例输出

23

这道题感觉理解起来,有点不严谨啊有木有。。一个板子从长度为[0,10]的范围里,应该在点0处不会掉下去啊,,但是,这个题貌似设计的是0处会掉下去,但是,题目里面又写的是“如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。”但是如果0处落下去的地方是前一个点,就是-1的话,那么“-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000”这个闭区间的端点处,会不会下落呢?好吧。。根据程序来看,在这个点貌似可以落下去,后来加了等号才AC的。。。好吧好吧,不纠结了。。。。

这道题可以用递推的方法做,从最下面的一个板子开始,一直赋值到最上面的板子,具体就是:

dp[i] [0]和dp[i][1]分别是这个板子从左端和右端到地面的距离,最下边的板子初始化为它的高度即可。p_v是存储板子的,具体递推公式是:

dp[i][0]=dp[i][0] = p_v[i].h - p_v[m].h + min(dp[m][0]+p_v[i].l-p_v[m].l, dp[m][1]+p_v[m].r-p_v[i].l)

dp[i][1] = p_v[i].h - p_v[m].h + min(dp[m][0]+p_v[i].r-p_v[m].l, dp[m][1]+p_v[m].r-p_v[i].r)

注意,有个限定条件,最大距离。。把程序写完加上去就好啦,两个板子之间的距离也要算进去的。。

c++版:

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
struct Point{
    int l;
    int r;
    int h;
    Point(int _l, int _r, int _h):l(_l), r(_r), h(_h){};
    bool operator < (const Point &p) const{
        return h<p.h;
    }
};
vector <Point> p_v;
int dp[1010][2];

int find_black(int index, int p){
    //从这个板子的下面的那个板子开始找,下面的if不加等号就错了哦~
    for (int i = index-1; i >= 0; i--) {
        if(p_v[i].l<=p && p_v[i].r>=p){
            return i;
        }
    }
    return inf;
}
int drop(int n, int maxs){
    dp[0][1]=dp[0][0]=p_v[0].h;//0代表左边的点,1代表右边的点
    int m;
    for (int i = 1; i <= n; ++i) {
        //更新这个板子左边的点
        if((m=find_black(i, p_v[i].l))!=inf){
            //下面有板子
            if((p_v[i].h - p_v[m].h)<=maxs)
                dp[i][0] = p_v[i].h - p_v[m].h + min(dp[m][0]+p_v[i].l-p_v[m].l, dp[m][1]+p_v[m].r-p_v[i].l);
            else
                dp[i][0] = inf;
        }
        else{
            if (p_v[i].h>maxs) dp[i][0] = inf;
            else {
                dp[i][0] = p_v[i].h;
            }
        }
        //更新板子右边的点
        if((m=find_black(i, p_v[i].r))!=inf){
            //下面有板子
            if((p_v[i].h-p_v[m].h)<=maxs){
                dp[i][1] = p_v[i].h - p_v[m].h + min(dp[m][0]+p_v[i].r-p_v[m].l, dp[m][1]+p_v[m].r-p_v[i].r);
            }
            else
                dp[i][1] = inf;
        }
        else{
            if (p_v[i].h>maxs) dp[i][1] = inf;
            else dp[i][1] = p_v[i].h;
        }
    }
    return min(dp[n][0], dp[n][1]);
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        int n, x, y, maxs;
        cin>>n>>x>>y>>maxs;
        memset(dp, 0, sizeof(dp));//初始化为0
        p_v.clear();//将vector清零
        //填充p_v并且按照这些point里面的h从小到大排序
        p_v.push_back(Point(x, x, y));
        for (int i = 0; i < n; ++i) {
            int x1, x2, h;
            cin>>x1>>x2>>h;
            p_v.push_back(Point(x1, x2, h));
        }
        sort(p_v.begin(), p_v.end());
        cout<<drop(n, maxs)<<endl;
    }
    return 0;
}

这里写图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值