poj1661 Help Jimmy(DP)

本文详细解析了POJ 1661题目的解题思路及DP算法实现。通过动态规划方法,针对不同路径选择计算出到达终点的最短时间。文章提供了完整的代码示例,并对关键步骤进行了注释说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:

http://poj.org/problem?id=1661

题目大意:中文题。

思路:这个题目可以用DP。

对于这个问题,要求总的时间最短。如果在某一块板上,可以选择往左或者往右走。如果此刻我们知道了往左走和往右走到达地面所用的最短时间,那么我们就可以判断出往哪个方向走是最优的。如果我们设置dp[i][j],dp[0][i]表示在第i块板上往左走的最短时间,dp[1][i]表示在第i块板上往右走的最短时间,可以得到状态转移方程:

dp[0][i]=h[i]-h[j]+min(dp[0][j]+x1[j]-x1[i],dp[1][j]+x2[i]-x1[j]);

dp[1][i]=h[i]-h[j]+min(dp[0][j]+x2[i]-x1[j],dp[1][j]+x2[j]-x2[i]);

注意要对木板的高度进行排序,这里可以从小到大进行排序。

这里还有一个要点就是:可能他可以直接跳。所以要额外判断。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int min(int a,int b)
{
	if(a<b)return a;
	else return b;
}
struct node {
	int x1,x2,h;
}p[1005];
bool cmp(node a,node b)
{
	if(a.h==b.h)return a.x1<b.x1;
	return a.h<b.h;
}
int main()
{
int T,i,j,k,dp[2][20005],n,x,y,MAX,sum,as;
bool f;
 scanf("%d",&T);
 while(T--)
 {
 	sum=0;
 	memset(dp,0,sizeof(dp));
 	scanf("%d%d%d%d",&n,&x,&y,&MAX);
 	for(i=1;i<=n;i++)
 	scanf("%d%d%d",&p[i].x1,&p[i].x2,&p[i].h);
 	sort(p+1,p+1+n,cmp);

 p[n+1].x1=x;p[n+1].x2=x;
 p[n+1].h=y;       //最后一个赋为起点。
 	for(i=1;i<=n+1;i++)         //从低到高来看,求得dp的最优值
 	{
 	 f=false;
	 	for(j=i-1;j>0;j--)     //左
	 	{
	 		
	 		if(p[i].h-p[j].h<=MAX&&p[i].h>p[j].h)   //这里要判断是否不超过最大高度。
	 		{
	 			if(p[j].x1<=p[i].x1&&p[i].x1<=p[j].x2)    //判断是否可以跳到下一块,一旦可以就跳下去,因为也只能跳下去。
			 {	dp[0][i]=p[i].h-p[j].h+min(dp[0][j]+p[i].x1-p[j].x1,dp[1][j]+p[j].x2-p[i].x1);
			 f=true;
			    break;
			 }
	 	  
	 	}
		 	}
		 if(p[i].h-p[0].h>MAX&&f==false)dp[0][i]=99999999;    //如果没有一块可以跳,那么就直接跳到地面
		 else if(f==false)dp[0][i]=p[i].h;
		 	 f=false;
	 	for(j=i-1;j>0;j--)           //右
	 	{
	 		if(p[i].h-p[j].h<=MAX&&p[i].h>p[j].h)
	 		{
		 		   if(p[i].x2>=p[j].x1&&p[j].x2>=p[i].x2)
	 	     {dp[1][i]=p[i].h-p[j].h+min(dp[0][j]+p[i].x2-p[j].x1,dp[1][j]+p[j].x2-p[i].x2);
	 	   f=true;
	 	     break;}
		 }
		 	}
       if(p[i].h-p[0].h>MAX&&f==false)dp[1][i]=99999999;
       else if(f==false)dp[1][i]=p[i].h;
	 }
	 printf("%d\n",min(dp[0][n+1],dp[1][n+1]));
 }
 return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值