对于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;
}