POJ-1661 Help Jimmy

动规,d[i][j]数组里存放:到达 高度为i 横坐标为j 的位置 最少需要多少横向移动
每次递推时从下落点或者平台两端开始,向下寻找平台或者地面,找到后更新平台两端的d[i][j]
题目中给出的数据量比较大,不能直接开d数组,需要先离散化处理一下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
const int N=1000+10;
struct node
{
	int x1,x2,h;
	bool operator < (const node &u) const
	{
		return h<u.h;
	}
}ban[N];
int hen[2*N],shu[N];
int h_cnt,s_cnt;
int d[N][2*N]; 
void m_min(int i,int j,int v) //取最小值函数
{
	if(d[i][j]==-1)
		d[i][j]=v;
	else
		d[i][j]=min(d[i][j],v);
}
int main()
{
	int T;
	int n,x,y,m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d%d",&n,&x,&y,&m);
		h_cnt=s_cnt=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d%d",&ban[i].x1,&ban[i].x2,&ban[i].h);
			hen[h_cnt++]=ban[i].x1;
			hen[h_cnt++]=ban[i].x2;
			shu[s_cnt++]=ban[i].h;
		}
		//离散化
		hen[h_cnt++]=x;
		shu[s_cnt++]=y;
		shu[s_cnt++]=0;
		sort(ban,ban+n);
		sort(hen,hen+h_cnt);
		sort(shu,shu+s_cnt);
		int t=1;
		for(int i=1;i<h_cnt;i++)
			if(hen[i]!=hen[i-1])
				hen[t++]=hen[i];
		h_cnt=t;
		t=1;
		for(int i=1;i<s_cnt;i++)
			if(shu[i]!=shu[i-1])
				shu[t++]=shu[i];
		s_cnt=t;
		for(int i=0;i<n;i++)
		{
			ban[i].x1=lower_bound(hen,hen+h_cnt,ban[i].x1)-hen;
			ban[i].x2=lower_bound(hen,hen+h_cnt,ban[i].x2)-hen;
			ban[i].h=lower_bound(shu,shu+s_cnt,ban[i].h)-shu;
		}
		x=lower_bound(hen,hen+h_cnt,x)-hen;
		y=lower_bound(shu,shu+s_cnt,y)-shu;
		//动规
		memset(d,-1,sizeof(d));
		d[y][x]=0; //起始位置
		for(int i=y;i>0;i--) //从高到低递推
		{
			for(int j=0;j<h_cnt;j++)
				if(d[i][j]!=-1) //已经到达的位置
				{
					bool flag=false;
					for(int k=n-1;k>=0;k--) //从高到低寻找可以落上的平台
						if(ban[k].h<i) //在i之下
						{
							int h=ban[k].h;
							if(shu[i]-shu[h]>m) break; //超过下落高度限制
							if(ban[k].x1<=j&&ban[k].x2>=j)
							{
								m_min(h,ban[k].x1,d[i][j]+hen[j]-hen[ban[k].x1]); //更新平台左边
								m_min(h,ban[k].x2,d[i][j]+hen[ban[k].x2]-hen[j]); //更新平台右边
								flag=true;
								break;
							}
						}
					if(!flag&&shu[i]<=m) //如果没有落上平台&&可以降落到地面
						m_min(0,j,d[i][j]);
				}
		}
		//得出答案
		int ans=-1;
		for(int i=0;i<h_cnt;i++)
			if(d[0][i]!=-1)
			{
				if(ans==-1)
					ans=d[0][i];
				else
					ans=min(ans,d[0][i]);
			}
		ans+=shu[y];
		printf("%d\n",ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值