poj1661(dp)

题目链接
数组含义:dp[i][0]:Jimmy 落在平台 i 并走到平台 i 左边需要的最短时间,dp[i][1] 是右边
flag[i][0]:从平台 i 左端落下有没有落到其他平台上,flag[i][1] 是右端
思路:先按高度从大到小排序,再找到 Jimmy 第一次落下的平台,如果有,记下下标 i 并更新 dp[i][0]、dp[i][1];如果没有直接输出 y。如果从平台 j 可以落到平台 i 上(即平台 j 比平台 i 的高度高,高度差小于等于MAX, j 的左端点或右端点(分两种情况写)在 i 的 x1,x2 中间且平台 i,j之间没有别的平台),看是否能更新 dp[i][0] 及 dp[i][1]。最后找到可以直接落在地面的平台,加上该平台的高度找一个最小值输出

#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define mem(x,y) memset(x,y,sizeof x)
#define cl1(x,y,n) for(int c1_i=0;c1_i<n;c1_i++) x[c1_i]=y
#define cl2(x,y,n,m) for(int c2_i=0;c2_i<n;c2_i++) for(int c2_j=0;c2_j<m;c2_j++) x[c2_i][c2_j]=y
#define inf (~0U>>2)
using namespace std;
const int maxn=1e3+10;
const int maxm=1e3+10;
struct node{int x1,x2,h;}a[maxm];
int n,x,y,m,dp[maxn][2];
bool flag[maxn][2];
bool cmp(node b,node c)
{
    return b.h>c.h;
}
bool judge(int b,node c)
{
    if(b>=c.x1&&b<=c.x2)
        return true;
    return false;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>x>>y>>m;
        cl2(dp,inf,n,2);
        mem(flag,false);
        for(int i=0;i<n;i++) cin>>a[i].x1>>a[i].x2>>a[i].h;
        sort(a,a+n,cmp);
        int id=inf;
        for(int i=0;i<n;i++)
            if(judge(x,a[i]))
                {id=i,dp[i][0]=x-a[i].x1+y-a[i].h,dp[i][1]=a[i].x2-x+y-a[i].h;break;}
        if(id==inf) {cout<<y<<endl;continue;}
        for(int i=id+1;i<n;i++)
        {
            for(int j=id;j<i;j++)
            {
                if(a[i].h<a[j].h&&a[j].h-a[i].h<=m&&judge(a[j].x1,a[i])&&!flag[j][0])///平台 j 的左端可以落在 平台 i
                {
                    flag[j][0]=true;
                    dp[i][0]=min(dp[i][0],dp[j][0]+a[j].h-a[i].h+a[j].x1-a[i].x1);
                    dp[i][1]=min(dp[i][1],dp[j][0]+a[j].h-a[i].h+a[i].x2-a[j].x1);
                }
                if(a[i].h<a[j].h&&a[j].h-a[i].h<=m&&judge(a[j].x2,a[i])&&!flag[j][1])///平台 j 的右端可以落在 平台 i
                {
                    flag[j][1]=true;
                    dp[i][0]=min(dp[i][0],dp[j][1]+a[j].h-a[i].h+a[j].x2-a[i].x1);
                    dp[i][1]=min(dp[i][1],dp[j][1]+a[j].h-a[i].h+a[i].x2-a[j].x2);
                }
            }
        }
        int ans=inf;
        for(int i=id;i<n;i++)
        {
            if(!flag[i][0]&&a[i].h<=m) ans=min(ans,dp[i][0]+a[i].h);///平台 i 左端不会落在其他平台且高度不大于MAX
            if(!flag[i][1]&&a[i].h<=m) ans=min(ans,dp[i][1]+a[i].h);///平台 i 右端不会落在其他平台且高度不大于MAX
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值