POJ 1661 Help Jimmy(二维DP)
题目链接:http://poj.org/problem?id=1661
题目大意:
![](http://poj.org/images/1661_1.jpg)
如图包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处(高H处)开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy到底地面时可能的最早时间。
解题思路:根据题意易得无论如何都要下落H的高度,所以可以不用计算下落高度所需时间,直接计算水平走的最短时间最后加上高度即可,按平台高度从高到低排序,建立二维数组,dp[i][0]表示第i个平台往左走到达地面的最短水平时间,dp[i][1]表示第i个平台往右走到达地面的最短水平时间,于是有状态转移方程:
dp[i][0]=min(dp[j][0]+a[i].x1-a[j].x1,dp[j][1]+a[j].x2-a[i].x1), j是i左边下面的落点平台编号。
dp[i][1]=min(dp[j][1]+a[j].x2-a[i].x2,dp[j][0]+a[i].x2-a[j].x1),j是i右边下面的落点平台编号。
所以直接自底向上递推,每次往左或往右找到第一个落点平台计算最少时间,最后推到i=0(起始点)就可以了。
要注意一下①初始化dp为inf,dp[0][1]和dp[0][0]也要初始化为inf。
②找到第一个可掉落的平台计算之后,就break,不然会把下面几个平台都算进去。
③判断当找不到落点平台时,可能有三种情况:
1)所在平台高度小于等于MAX,但下面没有平台
2)下面有平台,但两平台高度差大于MAX
3)下面没有平台,且所在平台高度大于MAX
特判情况1),此时dp[i][0](或dp[i][1])为0
代码:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=1e3+5; 5 const int inf=1<<30; 6 7 struct node{ 8 int x1,x2,h; 9 }a[N]; 10 11 int dp[N][2];//从第i层0往左,1往右 12 13 bool cmp(node a,node b){ 14 return a.h>b.h; 15 } 16 17 int main(){ 18 int T; 19 scanf("%d",&T); 20 while(T--){ 21 int n,X,H,MAX; 22 scanf("%d%d%d%d",&n,&X,&H,&MAX); 23 for(int i=1;i<=n;i++){ 24 scanf("%d%d%d",&a[i].x1,&a[i].x2,&a[i].h); 25 dp[i][0]=dp[i][1]=inf; 26 } 27 sort(a+1,a+1+n,cmp); 28 29 //将起始点也当成一个平台 30 a[0].h=H; 31 a[0].x1=a[0].x2=X; 32 dp[n][0]=dp[n][1]=0; 33 dp[0][0]=dp[0][1]=inf; 34 //自底向上推 35 for(int i=n-1;i>=0;i--){ 36 //往左走 37 for(int j=i+1;j<=n;j++){ 38 if(a[i].h-a[j].h<=MAX){ 39 if(a[j].x1<=a[i].x1&&a[j].x2>=a[i].x1){ 40 dp[i][0]=min(dp[j][0]+a[i].x1-a[j].x1,dp[j][1]+a[j].x2-a[i].x1); 41 break; 42 } 43 } 44 } 45 //下面没平台且里地面高度不超过MAX 46 if(a[i].h<=MAX&&dp[i][0]==inf) 47 dp[i][0]=0; 48 49 //往右走 50 for(int j=i+1;j<=n;j++) { 51 if(a[i].h-a[j].h<=MAX){ 52 if(a[j].x2>=a[i].x2&&a[j].x1<=a[i].x2){ 53 dp[i][1]=min(dp[j][1]+a[j].x2-a[i].x2,dp[j][0]+a[i].x2-a[j].x1); 54 break; 55 } 56 } 57 } 58 if(a[i].h<=MAX&&dp[i][1]==inf) 59 dp[i][1]=0; 60 } 61 printf("%d\n",min(dp[0][1],dp[0][1])+H); 62 } 63 return 0; 64 }