POJ 1661 Help Jimmy

Help Jimmy
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 13277 Accepted: 4408

Description

"Help Jimmy" 是在下图所示的场景上完成的游戏。 

场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。 

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

设计一个程序,计算Jimmy到底地面时可能的最早时间。 

Input

第一行是测试数据的组数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恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。 

Output

对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。

Sample Input

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

Sample Output

23

中文题意不解释。

这道题很明显要用dp了。

用dp[i][0]和dp[i][1]分别表示第i块木板从左端点出发到达地面的最短时间和第i块木板从右端点出发到达地面的最短时间。

具体的状态转移方程(以计算dp[i][0]为例)就是先找到左端正下方的木板,但这块木板并不一定是相邻的木板,而是要对之前的所有木板进行遍历,如果左端点处于当前正在遍历的木板的左右端点之间,则说明这块木板j就是左端点正下方的木板。

所以dp[i][0]就取第j块木板的左端点到达地面所花时间+到达左端点所花时间+两木板的高度差和右端点到达地面所花时间+到达右端点所花时间+两木板的高度差两者取小的那个。

坑点1:需要判断两者的高度差是否小于等于max_h

如果此端点正下方没有木板,那就判断当前木板距离地面的高度,如果小于max_h,dp[i][0]就等于这块木板的高度(直接跳至地面)否则就将这个值置为inf

右端点做相同的处理。

但这里其实还有一个trick。应该把最高点看作是一个长度为0,高度为Y,左端点=右端点=X的木板加入计算。

否则的话还需要多加一层判断。(因为最高点不一定跳到最高的一块木板上,甚至可以不跳到木板上直接跳至地面)

坑点2:边缘也算在木板上。

本来我处理的时候就是这么想的。

奈何、、、少打了一个等号orz wa了四五遍

果然写代码的时候还是要仔细啊。不要说像之前还把break漏掉等更多低级错误了。

下面上代码。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <string>
#include <iostream>
#include <math.h>
#include <queue>
#include <vector>
int n,t;
const int maxn = 3e4+10;
const int inf = 268430090;
using namespace std;
bool used[maxn];
char maze[50][50];
typedef pair<int,int> P;
int a[maxn];
int dp[maxn][2];
int dis[maxn];
typedef struct Node
{
    int x1,x2;
    int h;
} node;
int cmp(const void *a, const void *b)
{
    node pa = *(node*)a,pb = *(node*)b;
    return pa.h-pb.h;
}
int main()
{
    // std::ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    int N,X,Y,max_h;
    while(T--)
    {
        node a[maxn];
        scanf("%d%d%d%d",&N,&X,&Y,&max_h);
        memset(dp,-1,sizeof(dp));//一开始全部初始化为-1
        for(int i = 1; i <= N; i++)
            scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h);
        a[N+1].x1 = X;a[N+1].x2 = X;a[N+1].h = Y;//将出发点也加入进行计算
        qsort(a+1,N,sizeof(node),cmp);//按高度进行排序
        for(int i = 1; i <= N + 1; i++)
        {
            //计算左端点
            for(int j = i-1; j >= 1; j--)
            {
                if(a[i].x1 >= a[j].x1 && a[i].x1 <= a[j].x2 && a[i].h-a[j].h <= max_h)//要判断两点距离是否能跳
                {
                    dp[i][0] = min(a[i].x1 - a[j].x1 + dp[j][0],a[j].x2 - a[i].x1+dp[j][1]) + a[i].h - a[j].h;
                    break;
                }
            }
            if(dp[i][0] == -1)//如果当前端点下方没有木板
            {if(a[i].h <= max_h)dp[i][0] = a[i].h;
                else dp[i][0] = inf;}//否则置为inf
            for(int j = i-1; j >= 1; j--)
            {
                if(a[i].x2 >= a[j].x1 && a[i].x2 <= a[j].x2 && a[i].h-a[j].h <= max_h)
                {
                    dp[i][1] = min(a[i].x2 - a[j].x1 + dp[j][0],a[j].x2 - a[i].x2+dp[j][1]) + a[i].h - a[j].h;
                    break;
                }
            }
            if(dp[i][1] == -1)
            {if(a[i].h <= max_h)dp[i][1] = a[i].h;
                else dp[i][1] = inf;}
        }
        int ans = min(dp[N+1][0],dp[N+1][1]);
        printf("%d\n",ans);
        
    }

这道题好像还有建图然后用最短路做的。。

在练dp还是好好练吧。

唉 还是菜 这好像是简单dp题吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值