Help Jimmy

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
#include
#include
#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;
}

你可能感兴趣的:(Help Jimmy)