Help Jimmy

举报
ReCclay 发表于 2022/02/22 00:03:11 2022/02/22
【摘要】 Help Jimmy 四步走: 1.原问题分解为子问题 原问题:从最高点到地面所需要的时间 子问题:分为两个.从每个”相对”起点的左边走,或者从”相对结点的”右边走 2.确定状态 ...

Help Jimmy

四步走:

1.原问题分解为子问题

原问题:从最高点到地面所需要的时间
子问题:分为两个.从每个”相对”起点的左边走,或者从”相对结点的”右边走

2.确定状态

所谓的状态就是,各个路径沿途所经过的变量取值

在这个环境中对应起来就是, 各个路径中(从左边走||从右边走)沿途所经过变量(板子的编号)的取值

3.确定状态的边界值

边界不就是最后一行的取值(但是似乎这里不可深究太多,否则深陷递归的沼潭!)

4.确定状态的转移方程

假设从k 出发(看成点),k的正下方为m

LeftMinTime(k) = h(k) - h(m) + min(LeftMinTime(m)+ Lx(k)-Lx(m) +
RightMinTime(m)+Rx(m) - Rx(k) );

RightMinTime(k) = h(k) - h(m) + min(LeftMinTime(m)+Lx(k)-Lx(m) +
RightMinTime(m)+Rx(m) - Rx(k) );

再具体分析这个问题时就没那么麻烦了!
注:如果还实在理解不了,建议使用样例在IDE中单步执行,直至理解整个过程!

强调几个需要注意的事情:

1.首先要明确一件事,就是用户的标准输入的板子高度不是按照大小顺序排的,所以首先务必先把高度从高到低进行排序!
一下代码使用的是结构体排序用到cmp,如果不懂参参照另一篇博文:qsort理解

2.很明显每次都有两种选择可以使用,那么这时候就要有自己的主见了,
就是自己想怎样走一条路走到黑?(本例程是从左走到黑的)
这种思想颇像那个称硬币枚举那道题,可参见:称硬币

3.看代码注释


#include<stdio.h>
#include<memory.h>
#include<stdlib.h>
#define MAX_N 1000
#define INFINITE 1000000
int t,n,x,y,max;
struct Platform
{
    int Lx,Rx,h;
};
Platform aPlatform[MAX_N+10]; //用于存放相关板的信息 Lx Rx 以及 h
int aLeftMinTime[MAX_N+10];  //记录某个板(看编号)的左端点是否走过
int aRightMinTime[MAX_N+10]; //记录某个板(看编号)的右端点是否走过

int MyCompare(const void *a,const void *b)
{
    Platform *p1,*p2;
    p1=(Platform *)a;
    p2=(Platform *)b;
    return p2->h-p1->h;//实现降序排列
}

int MinTime(int L,bool bLeft)//这里定义成bool类型更节省空间
{
    int y=aPlatform[L].h;//表示“相对”起点的高度(一块板的左右选相对起点)
    int x,i;
    if(bLeft)//假如这块板左边没当过“相对”起点,那就让他做“相对”起点!
       x=aPlatform[L].Lx;
    else
        x=aPlatform[L].Rx;
    for(i=L+1;i<=n;i++)//判断相对“起点”下的板是否能走,不能走的话就继续找下下块板,直到找到或没板!
    {
        if(aPlatform[i].Lx <= x && aPlatform[i].Rx >= x)//判断下一块板的左右端点是否在“相对”起点两侧,至少重合?
            break;//在的话break掉
    }
    if(i<=n)//下一块板还存在
    {
        if( y - aPlatform[i].h > max )//判断是否会摔死
            return INFINITE;
    }
    else//没板了
    {
        if( y > max )//这里容易写错,注意是y在比较!
            return INFINITE;//摔死那就返回无穷大!
        else
            return y;//不会摔死返回高度差
    }
    int nLeftTime = y - aPlatform[i].h + x - aPlatform[i].Lx;//“相对”起点出发,从左所用时间
    int nRightTime = y - aPlatform[i].h + aPlatform[i].Rx - x;//“相对”起点出发,从右所用时间
    if( aLeftMinTime[i] == -1 )//这里的i已经自加,意即判断相对起点下的左端点是否做过“相对”起点?
        aLeftMinTime[i] = MinTime(i, true);//没有的话继续让他作为“相对”起点。 这里容易写错注意走左边就是true!
    if( aRightMinTime[i] == -1 )//同上,不过是右边
        aRightMinTime[i] = MinTime(i, false);
    nLeftTime += aLeftMinTime[i];//左边走的总时间
    nRightTime += aRightMinTime[i];//右边走的总时间
    if( nLeftTime < nRightTime )//返回最小值       
        return nLeftTime;
    else
        return nRightTime;
}//其实仔细想想 aLeftMinTime[i]、aRightMinTime[i] 何尝不是最优子结构性质的体现呢?

int main()
{
    int i,j;
/*  freopen("in.txt","r",stdin);*/
    scanf("%d", &t);
    for( i = 0;i < t; i ++ )
    {
        memset(aLeftMinTime, -1, sizeof(aLeftMinTime));
        memset(aRightMinTime, -1, sizeof(aRightMinTime));

        scanf("%d%d%d%d", &n, &x, &y, &max);
        aPlatform[0].Lx = x;
        aPlatform[0].Rx = x;
        aPlatform[0].h = y;

        for(j = 1; j <= n; j ++ )
            scanf("%d%d%d", & aPlatform[j].Lx, & aPlatform[j].Rx, & aPlatform[j].h);

        qsort(aPlatform, n+1, sizeof(Platform), MyCompare);

        printf("%d\n", MinTime(0, true));
    }

    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

文章来源: recclay.blog.csdn.net,作者:ReCclay,版权归原作者所有,如需转载,请联系作者。

原文链接:recclay.blog.csdn.net/article/details/62045897

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。