zoukankan      html  css  js  c++  java
  • poj 1661 动态规划 拯救老鼠

    题干在最后

    首先承认这道题用了我很多的时间,作为一个动态规划入门者兼vj新手,这道题对我来讲是比较有难度的。

    感想就是,设置判断条件时,一定要考虑全面,不要怕代码长;

    然后就是,对于动态规划,不应只把他当作一种套路甚至是解体模版;这样的话,你就总是想“拿条件,套公式”,对于dp,这种思想是危险而又行不同的。

    我觉得更应该把dp当作一种思想,解决、看待这类问题的一种角度,如果说对于dp题有套路,这个套路只能是dp的思想,而不应该包含代码之类的东西。

    在做这道题的同时我就犯了上述错误,在重新看了一遍北大的《算法基础》关于递归的部分后,我基本独立的写出来了自己的ac代码。

    网上有很多这道题的解析,但我觉得对入门者都不够友好,而且写的很杂乱,如果你也在入门dp,希望我的分享能对你有帮助。

    入门者的dp问题分析:

    在做dp问题时,可以先用递归的思想去考虑问题,先分解出整个求解过程中,其中一个完整的递归过程,然后考虑边界条件;

    对于这道题,我把从某平板的一端落下,再左右移动到所在平板的左or右端作为一个“完整的递归过程”,如图:

    其中四条铅笔线都可以看作一个完整的递归过程,如果你还不明白的话:

    铅笔线的起点到底部的最小路程,就等于铅笔线这条曲线的长度,加上终点到底部的最短路程;

    对于小老鼠一开始的下落,这个递归过程也是适用的。

    这里的递归,就是“归”到了“求一个点到底部的最短距离”这个问题上,也就是上面这句话的高亮部分。

    左右端点下落情况非常相似,我们要分开求,最终比较的就是,小老鼠一开始下落时,从板子左边掉下去和从右边掉下去那个路程更短。

    边界条件:如果点下方没有板子了,那就不再递归,而是返回点的高度(也就是点所在板子的高度)。

    然后问题是,如何判断端点下面有没有板子呢?

    这里,点的下方可能有板子,也可能没有板子,也可能有许多板子,很自然能能想到的办法是,我们将板子按高度排序,判断我们点所在的板子下方的那块板子,是不是在端点下方;这个判断就不难了,只需判断我们(小老鼠)所在板子的端点与下面那块板子的左右端点的关系就能得出结论。

    再然后,当用递归的函数直接求解dp问题时,中间过程往往会出现,某一个问题重复多次求解的现象(不理解的同学可以看看北大《算法基础》慕课第四章第一节,讲的非常好),浪费了时间与空间资源,这时我们的策略是,把每一个求解过的问题都存起来,下一次要求这个问题时就直接使用结果了。

    因此,根据我们所找出的递归过程的特点,我们从下往上求,这样上面的就可以用下面的板子端点的结果了;

    一直求到最高点,那么最终结果就是左侧下落,和右侧下落,结果中的最小值了。

    其中注意结构体排序的'>' '<'的结构体内的定义,这种方法非常简洁,应当记住。

    代码如下:(代码放上去排版有点诡异,不过并不影响阅读)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxn 1000+10
    #define inf 100000000

    int x,y,np,mh,lmt[maxn],rmt[maxn];

    struct flat{
    int l,r,h;
    friend bool operator < (flat a,flat b){
    return a.h<b.h;
    }
    }f[maxn];

    int qiu_lmt(int b){ //从b板左端点落下的最短路程,结果存于lmt[b]
    if(b==0){
    lmt[b]=f[b].h;
    // cout<<lmt[b]<<endl;
    return 0;
    }
    int x=-1;
    for(int i=b-1;i>=0;i--){
    if(f[i].l<=f[b].l && f[i].r>=f[b].l) //左端点下面有板子吗
    {x=i;break;}
    }

    if(x==-1) {
    if(f[b].h<=mh)
    {lmt[b]=f[b].h;
    // cout<<lmt[b]<<endl;
    }
    else {
    lmt[b]=inf;
    // cout<<lmt[b]<<endl;
    return 0;}
    }
    else if(f[b].h-f[x].h<=mh){
    lmt[b]=f[b].h-f[x].h+min(f[b].l-f[x].l+lmt[x],f[x].r-f[b].l+rmt[x]);
    // cout<<lmt[b]<<endl;
    return 0;
    }
    else {
    lmt[b]=inf;
    // cout<<lmt[b]<<endl;
    return 0;
    }
    }


    int qiu_rmt(int b){                             //从b板右端点落下的最短路程,结果存于rmt[b]
    if(b==0){
    rmt[b]=f[b].h;
    // cout<<rmt[b]<<endl;
    return 0;
    }
    int x=-1;
    for(int i=b-1;i>=0;i--){
    if(f[i].l<=f[b].r && f[i].r>=f[b].r)           //右端点下面有板子吗
    { x=i;break; }
    }

    if(x==-1) {
    if(f[b].h<=mh){rmt[b]=f[b].h;
    // cout<<rmt[b]<<endl;
    }else {
    rmt[b]=inf;
    // cout<<rmt[b]<<endl;
    return 0;}
    }
    else if(f[b].h-f[x].h<=mh){
    rmt[b]=f[b].h-f[x].h+min(f[b].r-f[x].l+lmt[x],f[x].r-f[b].r+rmt[x]);
    // cout<<rmt[b]<<endl;return 0;
    }
    else {
    rmt[b]=inf;
    // cout<<rmt[b]<<endl;
    return 0;
    }
    }

    int mintime(){
    for(int i=0;i<=np;i++){
    qiu_lmt(i);                      //从下至上,求出每个端点到底部的最短距离
    qiu_rmt(i);                      //结果与这俩函数先后次序无关
    }
    return rmt[np]>=lmt[np]?lmt[np]:rmt[np]; //求最小值
    }

    int main(){
    freopen("in.txt","r",stdin);
    int n;
    while(scanf("%d",&n)==1){
    while(n--){
    scanf("%d%d%d%d",&np,&x,&y,&mh);
    f[0].l=f[0].r=x;
    f[0].h=y;
    for(int i=1;i<=np;i++){
    scanf("%d%d%d",&f[i].l,&f[i].r,&f[i].h);
    }
    sort(f,f+np+1); //升序
    // cout<<f[0].h<<' '<<f[1].h<<' '<<f[2].h<<' '<<f[3].l<<' '<<f[3].r<<' '<<f[0].l<<' '<<f[0].r<<endl;
    cout<<mintime()<<endl;
    }
    }
    return 0;
    }

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


    场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
    Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
    设计一个程序,计算Jimmy到底地面时可能的最早时间。

    柳暗花明又一村
  • 相关阅读:
    Linq聚合操作之Aggregate,Count,Sum,Distinct源码分析
    Linq分区操作之Skip,SkipWhile,Take,TakeWhile源码分析
    Linq生成操作之DefautIfEmpty,Empty,Range,Repeat源码分析
    Linq基础操作之Select,Where,OrderBy,ThenBy源码分析
    PAT 1152 Google Recruitment
    PAT 1092 To Buy or Not to Buy
    PAT 1081 Rational Sum
    PAT 1084 Broken Keyboard
    PAT 1077 Kuchiguse
    PAT 1073 Scientific Notation
  • 原文地址:https://www.cnblogs.com/ucandoit/p/8435515.html
Copyright © 2011-2022 走看看