Help Jimmy POJ - 1661 数字三角DP

题意:中文 https://vjudge.net/problem/POJ-1661

题解:设两个dp数组,dpl[i]存 从第i块板左边到地上所花的最短时间,dpr[i]存右边的。

    将所有板按高度排序 ,从地面到人分别编号为0,1~n, n+1

坑:dp方程写错了个字母。

  一开始只用了一个dp数组(还改半天)

  没考虑同一高度

  人与地板算入dp数组时的赋值

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<cstring>
#include<set>
#include<algorithm>
#include<stack>
#include<string>
#include<cstdio>
#define _for(i, a, b) for (int i = (a); i<(b); ++i)
using namespace std;
const int N = 1e3 + 5;

struct plat {
    int l, r, h;
}p[N];
int dpl[N],dpr[N];//从第e块plat边缘一直掉到地上所需的最短时间
bool cmp(plat a, plat b) {
    return a.h < b.h;
}
int find(int x,int now) {
    if (now == 0) return 0;
    else for (int i = now-1; i >=0; i--) {
        if (p[i].h == p[now].h)continue;//改:同高度//其实不用考虑
        if (p[i].l <= x&&p[i].r >= x) return i;
    }
    return 0;//直接掉到地上
}
//大改:算法错误。
int main()                                  
{
    int t;
    cin >> t;
    while (t--) {
        _for(i, 0, N) dpl[i]=dpr[i] = 1e9;
        int n, x, y, mn;
        cin >> n >> x >> y >> mn;
        _for(i, 1, n+1) {cin >>p[i].l>>p[i].r>>p[i].h;}
        p[n+1].l = p[n+1].r = x; p[n+1].h = y;
        p[0].l = -2e6; p[0].r = 2e6; p[0].h = 0; //改:考虑掉到地上,不能这样改。
        sort(p, p + n+2,cmp);
        //查找落到下面的那一块:可以排序后二分
        _for(i, 1, n+1) {
            int idl= find(p[i].l,i), idr= find(p[i].r,i);
            if (idl == 0) { if (p[i].h <= mn) dpl[i] = p[i].h; }
            else if (p[i].h - p[idl].h <= mn) 
        { dpl[i] = min(dpl[i], dpl[idl] + p[i].h - p[idl].h + p[i].l - p[idl].l);
        dpl[i] = min(dpl[i], dpr[idl] + p[i].h - p[idl].h - p[i].l + p[idl].r);} if (idr == 0) { if (p[i].h <= mn) dpr[i] = p[i].h; } else if (p[i].h - p[idr].h <= mn) { dpr[i] = min(dpr[i], dpl[idr] + p[i].h - p[idr].h + p[i].r - p[idr].l); dpr[i] = min(dpr[i], dpr[idr] + p[i].h - p[idr].h - p[i].r + p[idr].r); } } int i = n + 1; int idl = find(p[i].l, i); if (idl == 0) { if (p[i].h - p[idl].h <= mn) dpl[i] = p[i].h - p[idl].h; } else if (p[i].h - p[idl].h <= mn) { dpl[i] = min(dpl[i], dpl[idl] + p[i].h - p[idl].h + p[i].l - p[idl].l); dpl[i] = min(dpl[i], dpr[idl] + p[i].h - p[idl].h - p[i].l + p[idl].r); } cout << dpl[n+1]<<endl; } system("pause"); }

 附记忆递归代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<cstring>
#include<set>
#include<algorithm>
#include<stack>
#include<string>
#include<cstdio>
#define _for(i, a, b) for (int i = (a); i<(b); ++i)
using namespace std;
const int N = 1e3 + 5;
const int INF = 1e6;
struct plat {
    int l, r, h;
    bool operator<(const plat &p2)const { return h > p2.h; }
}p[N];
int dpl[N],dpr[N],L[N];//从第e块plat边缘一直掉到地上所需的最短时间
bool cmp(plat a, plat b) {
    return a.h < b.h;
}
int find(int x,int now) {
    if (now == 0) return 0;
    else for (int i = now-1; i >=0; i--) {
        if (p[i].h == p[now].h)continue;//改:同高度
        if (p[i].l <= x&&p[i].r >= x) return i;
    }
    return 0;//直接掉到地上
}
int n, x, y, mn;
int dpfun(int l, bool bleft) {
    int y = p[l].h, x;
    x = bleft ? p[l].l : p[l].r;
    int i;
    for ( i = l+1; i <= n; i++) if (p[i].l <= x&&p[i].r >= x) { break; }
        
        if (i <= n) { if (y - p[i].h >mn)  return INF;  }else {if(y>mn)return INF;else return y;}
        int nl = y - p[i].h + x - p[i].l;
        int nr = y - p[i].h + p[i].r - x;
        if (dpl[i] == -1)dpl[i] = dpfun(i, true);
        if (L[i] == -1)L[i] = dpfun(i, false);
        nl += dpl[i];
        nr += L[i];
        if (nl < nr)return nl; return nr;


    

}
//大改:算法错误。
int main()                                  
{
    int t;
    cin >> t;
    while (t--) {
        _for(i, 0, N) dpl[i] = dpr[i] =L[i]= -1;

        cin >> n >> x >> y >> mn;
        _for(i, 1, n + 1) { cin >> p[i].l >> p[i].r >> p[i].h; }

        p[0].l = x; p[0].r = x; p[0].h = y; //改:考虑掉到地上,不能这样改。
        sort(p, p + n + 1);
        //查找落到下面的那一块:可以排序后二分
        cout << dpfun(0, true) << endl;
    }
    system("pause");
} 

 

posted @ 2018-04-06 19:45  SuuTTT  阅读(184)  评论(0编辑  收藏  举报