POJ - 1661 Help Jimmy

题意:
从一个初始位置往下跳,中间有平台,问落到平台上的最小时间是多少

思路:
一开始想着dp[i][2]表示到达第i个平台时,上一步是从左或者右转移过来,但是这样的话状态有点难搞。

这题充分体现了DP的子问题重叠性,对于从第一个点到达终点的过程中,到底怎么分解才可以保证状态转移是方便的,为了排除转移时的状态冗杂,容易想到从一个节点跳下去的时候,只能被最先接到的平台接到,所以思考状态转移的思维方式的时候,两种都要考虑
1.当前状态如何由前一个状态转移过来
2.这个状态往下转移能怎么转移

依据题目选取最优的转移方式是必须的
该题很明显是第二种更好想
从第一个到终点可以分解为从第二个到终点…从第n个平台到终点的最短时间,所以从小的子问题倒序遍历,关键在于这样的状态转移选择第一次遇到能够跳下去的时候就可以停止了,与我一开始想的从上面转移下来的冗杂性完全不一样

所以dp[i][2]表示从第i个平台出发,往左或往右到终点的最小值,排序就按高度从小到大排,然后顺序遍历

代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1020;
struct Node{ 
    int l,r,h;
    bool operator<(const Node&a)const
    {
       return h<a.h; 
    }
}node[maxn];
int dp[maxn][2];
int main()
{
    int t,n,l,r,maxh;
    scanf("%d",&t);
    while(t--)
    { 
       memset(dp,0x3f,sizeof(dp));
       scanf("%d%d%d%d",&n,&l,&r,&maxh);
       for(int i=0;i<n;++i) 
            scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].h);
       node[n].l=l,node[n].r=l,node[n].h=r;
       sort(node,node+n);
       int lp,rp;
       for(int j=0;j<=n;++j)
       {
          lp=rp=-1;
          for(int k=j-1;k>=0;--k)
          {
             if(lp==-1&&node[k].l<=node[j].l&&node[k].r>=node[j].l)
                lp=k;
             if(rp==-1&&node[k].l<=node[j].r&&node[k].r>=node[j].r)
                rp=k; 
          } 
          if(lp==-1&&node[j].h<=maxh)//左下方没有但能落地时
              dp[j][0]=node[j].h;
          if(rp==-1&&node[j].h<=maxh)//右下方没有但能落地时
              dp[j][1]=node[j].h;
          if(lp!=-1&&node[j].h-node[lp].h<=maxh)
              dp[j][0]=min(dp[lp][0]+node[j].l-node[lp].l,dp[lp][1]+node[lp].r-node[j].l)+node[j].h-node[lp].h;
          if(rp!=-1&&node[j].h-node[rp].h<=maxh)
              dp[j][1]=min(dp[rp][1]+node[rp].r-node[j].r,dp[rp][0]+node[j].r-node[rp].l)+node[j].h-node[rp].h;
       }
       printf("%d\n",dp[n][0]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值