poj 1661 动态规划

原题请参考poj 1661

思路:先用一个struct将板子表示出来,再按高度对他们进行排序,

问题简化为对板子的处理。

mintime=下落时间+min{向左走最小时间,向右走最小时间};

同时进行动态规划,将时间存在两个数组中

#include<iostream>

#include<algorithm>
using namespace std;
const int manx = 40001;
struct Block{
int X1,X2,H;
};
bool compare(Block b1,Block b2){
return b1.H > b2.H;
}
Block blocks[manx];
int fall(int X,int Y,int maax);
int leftTime[manx + 10];
int rightTime[manx + 10];
int leftMinTime(int k);
int rightMinTime(int k);
int leftWhetherDown(int k);
int rightWhetherDown(int k);
int n,X,Y,maax;
int main(){
int t;
scanf("%d",&t);
while(t--)
{
memset(leftTime,-1,sizeof(leftTime));
memset(rightTime,-1,sizeof(rightTime));
cin>>n>>X>>Y>>maax;
blocks[0].X1 = blocks[0].X2 = X;
blocks[0].H = Y;
for(int i = 1;i <= n;i++)
{
scanf("%d%d%d",&blocks[i].X1,&blocks[i].X2,&blocks[i].H);
}
sort(blocks+1,blocks+n+1,compare);
int minTime = min(leftMinTime(0),rightMinTime(0));
printf("%d\n",minTime);
}
return 0;
}
int leftMinTime(int k){
int result(0);
int tmp = leftWhetherDown(k);
if(tmp == 0 )
{
if(blocks[k].H > maax)
return 1000000;
else
return blocks[k].H;
}
else
{
if(blocks[k].H - blocks[tmp].H > maax)
return 10000000;
int Ltmp,Rtmp;
if(leftTime[tmp] != -1)
Ltmp = leftTime[tmp];
else
Ltmp = leftMinTime(tmp);
if(rightTime[tmp] != -1)
Rtmp = rightTime[tmp];
else
Rtmp = rightMinTime(tmp);
result = (blocks[k].H - blocks[tmp].H) + 
min((blocks[k].X1 - blocks[tmp].X1 + Ltmp),(blocks[tmp].X2 - blocks[k].X1 + Rtmp));


}
leftTime[k] = result;
return result;
}


int rightMinTime(int k){
int result(0);
int tmp = rightWhetherDown(k);
if(tmp == 0 )
{
if(blocks[k].H > maax)
return 1000000;
else
return blocks[k].H;
}
else
{
if(blocks[k].H - blocks[tmp].H > maax)
return 10000000;
result = (blocks[k].H - blocks[tmp].H) + 
min((blocks[k].X2 - blocks[tmp].X1 + leftMinTime(tmp)),(blocks[tmp].X2 - blocks[k].X2 + rightMinTime(tmp)));


}
rightTime[k] = result;
return result;
}
int leftWhetherDown(int k){
int i,result(0);
for(i = k + 1;i <= n;i++)
{
if((blocks[i].X1 <= blocks[k].X1) && (blocks[i].X2 >= blocks[k].X1))
{
result = i;
break;
}
}
return result;
}
int rightWhetherDown(int k){
int i,result(0);
for(i = k + 1;i <= n;i++)
{
if((blocks[i].X1 <= blocks[k].X2) && (blocks[i].X2 >= blocks[k].X2))
{
result = i;
break;
}
}
return result;

}

递推算法(程序设计实习答案)

///

//递推的程序:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define MAX_N 1000
#define INFINITE 1000000
int t,n,x,y,maxHeight;
struct Platform{
int Lx, Rx, h;
bool operator < (const Platform & p2) const {
return h > p2.h;
}
};
Platform platforms[MAX_N + 10];
int leftMinTime[MAX_N + 10]; //各板子从左走最短时间
int rightMinTime[MAX_N + 10]; //各板子从右走最短时间
int main() 
{
scanf("%d",&t);
while( t--) {
scanf("%d%d%d%d",&n, &x, &y, &maxHeight);
platforms[0].Lx = x; platforms[0].Rx = x; platforms[0].h = y;
for( int j = 1; j <= n; j ++ )
scanf("%d%d%d",&platforms[j].Lx,& platforms[j].Rx, 
& platforms[j].h);
sort(platforms,platforms+n+1);
for( int i = n ; i >= 0; -- i ) {
int j;
for( j = i + 1; j <= n ; ++ j ) { //找i的左端的下面那块板子
if( platforms[i].Lx <= platforms[j].Rx 
&& platforms[i].Lx >= platforms[j].Lx)
break;
}
if( j >n ) { //找不到
if( platforms[i].h > maxHeight )
leftMinTime[i] = INFINITE;
else
leftMinTime[i] = platforms[i].h;
}
else {
int y = platforms[i].h - platforms[j].h; 
if( y > maxHeight)
leftMinTime[i] = INFINITE;
else
leftMinTime[i] = y + 
min(leftMinTime[j]+platforms[i].Lx-platforms[j].Lx,
rightMinTime[j]+platforms[j].Rx-platforms[i].Lx);
}
for( j = i + 1; j <= n ; ++ j ) { //找i的右端的下面那块板子
if( platforms[i].Rx <= platforms[j].Rx 
&& platforms[i].Rx >= platforms[j].Lx)
break;
}
if( j > n ) {
if( platforms[i].h > maxHeight )
rightMinTime[i] = INFINITE;
else rightMinTime[i] = platforms[i].h;
}
else {
int y = platforms[i].h - platforms[j].h;
if( y > maxHeight) rightMinTime[i] = INFINITE;
else
rightMinTime[i] = y + 
min(leftMinTime[j]+platforms[i].Rx-platforms[j].Lx,
rightMinTime[j]+platforms[j].Rx-platforms[i].Rx);
}
}
printf("%d\n", min(leftMinTime[0],rightMinTime[0]));
}
return 0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值