[DP] POJ1661


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


找到下落的最短时间


大概就是已知下面的算上面的?自底向上的步骤然后找出左右当中较小的就完成了DP优化?( ̄▽ ̄)

果然还是不太懂DP的套路hhh

和网上的代码一模一样系列



#include <algorithm>
#include <cstdio>
#include <iostream>

#define INF 999999999;

int N, X, Y, MAX;
int T[ 1010 ][ 2 ];

struct Plate {
        int x1, x2, h; //左坐标,右坐标,高度
} p[ 1010 ];

bool cmp ( const Plate &a, const Plate &b ) { return a.h < b.h; } //按照高度排序的比较函数

int min ( int a, int b ) { return a < b ? a : b; }

void left ( int i ) { //从板子i的左侧下落的最短时间
        int k = i - 1;
        while ( k > 0 && p[ i ].h - p[ k ].h <= MAX ) { //找到比自己矮的,且两者之间距离不超过MAX
                if ( p[ i ].x1 >= p[ k ].x1 &&
                     p[ i ].x1 <= p[ k ].x2 ) { //板子i的x1(左侧)处于板子k的x1,x2之间
                        T[ i ][ 0 ] =
                            ( p[ i ].h - p[ k ].h ) +
                            min ( ( T[ k ][ 0 ] + p[ i ].x1 - p[ k ].x1 ),
                                  ( T[ k ][ 1 ] + p[ k ].x2 - p[ i ].x1 ) ); //计算较短的时间
                        return;
                }
                k--;
        }
        if ( p[ i ].h > MAX ) { //如果左侧下方已经没有其他板子(不满足上方的if)
                T[ i ][ 0 ] = INF; //高度超过MAX则无解
        } else
                T[ i ][ 0 ] = p[ i ].h; //未超过则直接落地
}

void right ( int i ) { //从板子i的右侧下落的最短时间
        int k = i - 1;
        while ( k > 0 && p[ i ].h - p[ k ].h <= MAX ) {
                if ( p[ i ].x2 >= p[ k ].x1 &&
                     p[ i ].x2 <= p[ k ].x2 ) { //板子i的x2(右侧)处于板子k的x1,x2之间
                        T[ i ][ 1 ] = ( p[ i ].h - p[ k ].h ) +
                                      min ( ( T[ k ][ 0 ] + p[ i ].x2 - p[ k ].x1 ),
                                            ( T[ k ][ 1 ] + p[ k ].x2 - p[ i ].x2 ) );
                        return;
                }
                k--;
        }
        if ( p[ i ].h > MAX ) {
                T[ i ][ 1 ] = INF;
        } else
                T[ i ][ 1 ] = p[ i ].h;
}

int Time () {
        for ( int i = 1; i <= N + 1; i++ ) { //从最低的板子开始向上计算
                right ( i );
                left ( i );
        }
        return min ( T[ N + 1 ][ 0 ], T[ N + 1 ][ 1 ] ); //返回左右侧较短的时间值
}

int main () {
        int t;
        scanf ( "%d", &t );
        while ( t-- ) {
                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]代表地面
                p[ 0 ].h = 0;
                p[ 0 ].x1 = -20000;
                p[ 0 ].x2 = 20000;

                // p[ N+1 ]代表jimmy所在的位置
                p[ N + 1 ].h = Y;
                p[ N + 1 ].x1 = X;
                p[ N + 1 ].x2 = X; //左右坐标都设置为当前的X位置

                std::sort ( p, p + N + 2, cmp );

                printf ( "%d\n", Time () );
        }
        return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值