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

来源:互联网 发布:淘宝买精密管会查吗 编辑:程序博客网 时间:2024/06/05 00:47

好吧,这道题我交了第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]);}


0 0