poj1661 dp+dfs好题

16 篇文章 0 订阅

对于dp加dfs的题目,一直不太熟练,要训练一下才行。这题思路不难想到,关键是怎么编程实现。

思路:从每块板(把最上面的点想象成一块长度为0的板)往下掉的的最短时间,必然是左边的下降的时间和右边下降时间取最短,然后递推式简单谢啦就是dp[seg_id][0]=min(dp[seg_id+1][0],dp[seg_i][1])+平台下落之间的时间+下降后跑到下一个平台一端的时间。(这个地方写的时候很容易错乱)

但是这个思路如果像普通的简单dp循环刷表的话比较困难,所以就要借助递归dfs,(这个有点类似二叉树的遍历),求出从某一个平台左侧还是右侧下落的时间,比较得出最小值。


/*以下代码统一0表示向左,1表示向右*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e3+50;
int t,n,x,heigh,max_heigh,ans_heigh[maxn][2];///记录从某一平台向左或向右下落的时间

struct seg{
	int x1,x2,heigh;
	seg(int xx,int yy,int hh):x1(xx),x2(yy),heigh(hh){
	}
	seg(){
	}
};

bool cmp(seg a,seg b){
	return a.heigh>b.heigh;
}

int dfs(int seg_id,int left_right,seg s[],int xx){
	if(ans_heigh[seg_id][left_right]!=-1) return ans_heigh[seg_id][left_right];///如果这个平台向左或向右已经得出过最短时间
	int left,right;
	left=right=inf;
	bool flg=true;
	for(int i=seg_id+1;i<=n;i++){
		int between_heigh=s[seg_id].heigh-s[i].heigh;
		if(between_heigh>max_heigh){
			flg=false;
			break; 
		} 
		if(xx>=s[i].x1&&xx<=s[i].x2){
			left=dfs(i,0,s,s[i].x1)+between_heigh+xx-s[i].x1;
			right=dfs(i,1,s,s[i].x2)+between_heigh+s[i].x2-xx;
			flg=false;
			break;
		}
	}
	ans_heigh[seg_id][left_right]=min(left,right);
	if(flg&&s[seg_id].heigh<=max_heigh){///如果走到最后一层
		ans_heigh[seg_id][left_right]=s[seg_id].heigh;
	}
	return ans_heigh[seg_id][left_right];
}

int main(){
	while(scanf("%d",&t)!=EOF){
		for(int i=0;i<t;i++){
			memset(ans_heigh,-1,sizeof(ans_heigh));
			seg s[maxn];
			scanf("%d%d%d%d",&n,&x,&heigh,&max_heigh);
			for(int j=1;j<=n;j++){
				scanf("%d%d%d",&s[j].x1,&s[j].x2,&s[j].heigh);
			}			
			s[0].x1=s[0].x2=x;///把初始点看成一个平台 
			s[0].heigh=heigh;
			sort(s,s+n+1,cmp);///按平台高度从大到小排序
			printf("%d\n",dfs(0,1,s,x));///从第0号平台开始下降
		}
	}
	return 0;
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值