Help Jimmy POJ - 1661
考察:线性dp
错误思路:
f[x][y]代表坐标(x,y)的最少时间,状态转移方程推不出来,而且完全没有用到木板
正确思路:
上面的状态表示其实比较接近.dp问题要将大问题分解为若干个小问题.将起始点看作一块木板,f[i][0]表示从左边跳下去的最短时间,f[i][1]表示从右边跳下去的最短时间.,每一个新的状态都由右边或者左边转移而来,两者求min.
要注意的是:当从某端点已经确定会掉在某块木板上时,就不可能掉在其他木板上
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int N = 1010,INF = 0x3f3f3f3f; 7 struct FLoor{ 8 int l,r,h; 9 bool operator<(FLoor x) 10 { 11 if(this->h==x.h) return this->l<x.l; 12 return this->h<x.h; 13 } 14 }floors[N]; 15 int f[N][2]; 16 void get(int i,int j,bool dir) 17 { 18 int l = floors[i].l,r = floors[i].r; 19 int a = floors[j].l,b = floors[j].r; 20 int h = floors[i].h-floors[j].h; 21 if(!dir)//从第i块的左边跳到第j的木块的左,右 22 { 23 int x = abs(l-a),y = abs(l-b); 24 f[i][dir] = min(x+f[j][0],y+f[j][1])+h; 25 }else{ 26 int x = abs(r-a),y = abs(r-b); 27 f[i][dir] = min(x+f[j][0],y+f[j][1])+h; 28 } 29 } 30 int main() 31 { 32 int T; 33 scanf("%d",&T); 34 while(T--) 35 { 36 int n,x,y,maxn; 37 scanf("%d%d%d%d",&n,&x,&y,&maxn); 38 for(int i=1;i<=n;i++) 39 scanf("%d%d%d",&floors[i].l,&floors[i].r,&floors[i].h); 40 sort(floors+1,floors+n+1); 41 floors[0].h = 0,floors[0].l = -INF,floors[0].r = INF; 42 floors[n+1].l = x,floors[n+1].r =x,floors[n+1].h = y; 43 for(int i=1;i<=n+1;i++) 44 { 45 f[i][1] = INF,f[i][0] = INF; 46 bool okl = 1,okr = 1; 47 for(int k=i-1;k>=1;k--) 48 { 49 int h = floors[i].h-floors[k].h; 50 if(h>maxn) break; 51 int l = floors[i].l,r= floors[i].r; 52 if(okl&&l>=floors[k].l&&l<=floors[k].r) 53 get(i,k,0),okl = 0; 54 if(okr&&r>=floors[k].l&&r<=floors[k].r) 55 get(i,k,1),okr = 0; 56 } 57 if(floors[i].h<=maxn) 58 { 59 if(okl) f[i][0] = min(f[i][0],floors[i].h); 60 if(okr) f[i][1] = min(f[i][1],floors[i].h); 61 } 62 } 63 printf("%d\n",f[n+1][0]); 64 } 65 return 0; 66 }