100道动态规划——22 POJ 1661 帮助 Jimmy 记忆化搜索 状态定义 以及一个思维上的漏洞

好吧,这道题我交了第9次才A

我觉得想到动态规划不是一件很难的事情.....我在状态的定义上犯了一个错误

我一开始定义的状态是dp[i][j]表示坐标在i,j时的花费的最小时间,这就导致数组开不下,于是我就用了一个map来存

然后记忆化搜索当然就是记录4个值了i,j,当前下落的高度,以及是从哪个方向走过来的

就WA了4~5次....感觉这样行不通

然后就看了题解,发现应该把状态定义为dp[i][k]其中k是0或1表示在第i个平台上最左或是最右边跳下后用的最少时间

这样一来就好写很多了嘛

记忆化搜索的时候要额外加两个,一个初始的平台(x,x,y),一个是地面,其实我感觉地面不加也可以,特判一下。不过初始的需要加上,因为从初始的地方落下后不一定是落在第一个平台上,有可能是第二个或者后面的平台上(注,这儿的平台已经按照高度从大到小排了序)

眼睛漏看了n的范围,误以为题目没给,于是就用了vector。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

struct Node{
    int x1,x2,h;
    bool operator< (const Node& a)const{return h>a.h;}
    explicit Node(int a=0,int b=0,int c=0):x1(a),x2(b),h(c){}
};

vector<Node> v;
vector<int> dp[2];

int n,x,y,m,t,ans,dfs(int x,int y);

int main(){
    ios_base::sync_with_stdio(false);
    cin>>t;
    while(t--){
        cin>>n>>x>>y>>m;
        v.resize(n);
        dp[0].resize(n+1,-1);
        dp[1].resize(n+1,-1);
        for(int i=0;i<n;++i)
            cin>>v[i].x1>>v[i].x2>>v[i].h;
        v.push_back(Node(x,x,y));
        sort(v.begin(),v.end());
        v.push_back(Node(-0x3f3f3f3f,0x3f3f3f3f,0));
        cout<<dfs(x,0)<<endl;
        dp[0].clear();
        dp[1].clear();
    }
    return 0;
}

int dfs(int x,int y){
    if(y==v.size()-1)
        return 0;
    if(dp[0][y]!=-1&&dp[1][y]!=-1)
        return min(x-v[y].x1+dp[0][y],v[y].x2-x+dp[1][y]);

    dp[0][y]=dp[1][y]=0x3f3f3f3f;
    for(int j=y+1;j<v.size()&&v[y].h-v[j].h<=m;++j){
        if(v[y].x1>=v[j].x1&&v[y].x1<=v[j].x2){
            dp[0][y]=min(dp[0][y],dfs(v[y].x1,j)+v[y].h-v[j].h);
            break;
        }
    }
    for(int j=y+1;j<v.size()&&v[y].h-v[j].h<=m;++j){
        if(v[y].x2>=v[j].x1&&v[y].x2<=v[j].x2){
            dp[1][y]=min(dp[1][y],dfs(v[y].x2,j)+v[y].h-v[j].h);
            break;
        }
    }
    return min(x-v[y].x1+dp[0][y],v[y].x2-x+dp[1][y]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值