POJ 1661 Help Jimmy DP
思路:Jimmy 跳到一块板上后,可以有两种选择,向左走或向右走。走到左端和走到右端所需的时间,容易算出。
n如果我们能知道,以左端为起点到达地面的最短时间,和以右端为起点到达地面的最短时间,那么向左走还是向右走,就很容选择了。
n因此,整个问题就被分解成两个子问题,即Jimmy 所在位置下方第一块板左端为起点到地面的最短时间,和右端为起点到地面的最短时间。这两个子问题在形式上和原问题是完全一致的。
详见代码
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define clc(a,b) memset(a,b,sizeof(a)) 6 #define LL long long 7 #include<cmath> 8 const int inf=0x3f3f3f3f; 9 using namespace std; 10 int n,X,Y,maxx; 11 int dp[1010][2];//0表示左边,1表示右边 12 struct node { 13 int x,y,h; 14 } plat[1010]; 15 16 int cmp(node p,node q) { 17 return p.h<q.h; 18 } 19 20 void left_solve(int i) { 21 int k=i-1; 22 while(k>0&&plat[i].h-plat[k].h<=maxx) { 23 if(plat[i].x>=plat[k].x&&plat[i].x<=plat[k].y) { 24 dp[i][0]=plat[i].h-plat[k].h+min(plat[i].x-plat[k].x+dp[k][0],plat[k].y-plat[i].x+dp[k][1]);//转移方程 25 return ; 26 } else 27 k--; 28 } 29 if(plat[i].h-plat[k].h>maxx) 30 dp[i][0]=inf; 31 else 32 dp[i][0]=plat[i].h; 33 } 34 35 void right_solve(int i) { 36 int k=i-1; 37 while(k>0&&plat[i].h-plat[k].h<=maxx) { 38 if(plat[i].y>=plat[k].x&&plat[i].y<=plat[k].y) { 39 dp[i][1]=plat[i].h-plat[k].h+min(plat[i].y-plat[k].x+dp[k][0],plat[k].y-plat[i].y+dp[k][1]); 40 return; 41 } else 42 k--; 43 } 44 if(plat[i].h-plat[k].h>maxx) 45 dp[i][1]=inf; 46 else 47 dp[i][1]=plat[i].h; 48 49 } 50 int solve() { 51 for(int i=1; i<=n+1; i++) { 52 left_solve(i); 53 right_solve(i); 54 } 55 return min(dp[n+1][0],dp[n+1][1]); 56 } 57 58 int main() { 59 // freopen("in.txt","r",stdin); 60 int t; 61 while(~scanf("%d",&t)) { 62 while(t--) { 63 scanf("%d%d%d%d",&n,&X,&Y,&maxx); 64 for(int i=1; i<=n; i++) { 65 scanf("%d%d%d",&plat[i].x,&plat[i].y,&plat[i].h); 66 } 67 plat[0].x=-20000;//加入地面和起始点 68 plat[0].y=20000; 69 plat[0].h=0; 70 plat[n+1].x=X; 71 plat[n+1].y=X; 72 plat[n+1].h=Y; 73 sort(plat,plat+n+2,cmp);//从低到高排序 74 // for(int i=0;i<=n+1;i++){ 75 // printf("%d\n",plat[i].h); 76 // } 77 clc(dp,0); 78 printf("%d\n",solve()); 79 } 80 } 81 return 0; 82 }