题意:中文 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"); }