分析:
将板子由高到低按从0到n编号,起始点的为0
不妨认为Jimmy开始的位置是一个编号为0,长度为0的板子
设LeftMinTime(k)表示从k号板子左端到地面的最短时间
RightMinTime(k)表示从k号板子右端到地面的最短时间
if ( 板子k左端正下方没有别的板子) {
if( 板子k的高度 h(k) 大于Max)
LeftMinTime(k) = ∞;
else
LeftMinTime(k) = h(k);
}
else if( 板子k左端正下方的板子编号是m )
LeftMinTime(k) = h(k)-h(m) +
Min( LeftMinTime(m) + Lx(k)-Lx(m),
RightMinTime(m) + Rx(m)-Lx(k));
}
代码:
我喜欢保留写代码过程中的调试细节,望体谅~
package 蓝桥杯;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
//sample input:
//1
//5 8 17 20
//0 10 8
//0 11 12
//0 10 13
//3 5 6
//4 14 3
public class VO动规_Help_Jimmy {
//人人为我递推型
static int N,X,Y,MAX;//小球下方平台个数N,Jimmy开始下落的位置的横竖坐标X Y,Jimmy一次下落的最大高度MAX
static PlatFrom[] platfroms;//平台的自定义对象
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
int t=reader.nextInt();
while(t!=0) {
N=reader.nextInt();
X=reader.nextInt();
Y=reader.nextInt();
MAX=reader.nextInt();
platfroms=new PlatFrom[N+1];
platfroms[0]=new PlatFrom(X, X, Y);//将小球的起点当作第一个平台
for(int i=1;i<N+1;i++) {
int L=reader.nextInt();
int R=reader.nextInt();
int H=reader.nextInt();
platfroms[i]=new PlatFrom(L, R, H);
}
//将平台从高到低排序
List<PlatFrom> pfList=new ArrayList<PlatFrom>(Arrays.asList(platfroms));//该方法是将数组转化为list,但是注意原数组却不会发生变化
Collections.sort(pfList);
int c=0;
for( PlatFrom e: pfList) {
System.out.println(e.toString());
platfroms[c++]=e;
}
//time[i][0]代表第个i平太左边为起点下落的最小时间。
//time[i][1]代表从第i个平台右边为起点下落的最小时间
int[][] time=new int[N+1][2];
//递推,详情请看伪代码
int m=0;
for(int k=N;k>=0;k--) {
// System.out.print("k= "+k+" ");
if(k==N) {//由于H[i]<MAX<Y一定,否则问题无解,最下面的板子左右端点到地面的距离为此块板子的高度
time[k][0]=platfroms[k].high;
// System.out.print("time["+k+"][0]= "+time[k][0]);
time[k][1]=platfroms[k].high;
// System.out.print(" time["+k+"][1]= "+time[k][1]);
}
else {
m=leftUnder(k);//判断第k个板子左端点下面是否存在可行的板子m
if(m==-1) {//不存在符合条件的板子m
if(platfroms[k].high>MAX) time[k][0]=999999;
else time[k][0]=platfroms[k].high;
// System.out.print("无m值 time["+k+"][0]= "+time[k][0]);
}
else {//存在板子m
time[k][0]=platfroms[k].high-platfroms[m].high+Math.min(time[m][0]+platfroms[k].Lx-platfroms[m].Lx, time[m][1]+platfroms[m].Rx-platfroms[k].Lx);
// System.out.print(" m= "+m+" time["+k+"][0]= "+time[k][0]);
}
m=rightUnder(k);//同理判断右断点
if(m==-1) {
if(platfroms[k].high>MAX) time[k][1]=999999;
else time[k][1]=platfroms[k].high;
// System.out.print("无m值 time["+k+"][1]= "+time[k][1]);
}
else {
time[k][1]=platfroms[k].high-platfroms[m].high+Math.min(time[m][0]+platfroms[k].Rx-platfroms[m].Lx, time[m][1]+platfroms[m].Rx-platfroms[k].Rx);
// System.out.print(" m= "+m+" time["+k+"][1]= "+time[k][1]);
}
}
// System.out.println();
}
System.out.println(time[0][1]);//输出从起始点出发所花的时间
t--;
}
}
static class PlatFrom implements Comparable<PlatFrom>{
private int Lx;
private int Rx;
private int high;
public PlatFrom(int x,int y,int z) {
this.Lx=x;
this.Rx=y;
this.high=z;
}
//为了更好得显示数据(实际上为测试所需),我们重写toString方法
@Override
public String toString() {
return "X="+Lx+",Y="+Rx+",Z="+high+"。";
}
public int getX() {
return Lx;
}
public int getY() {
return Rx;
}
public int getZ() {
return high;
}
//实现Comparable接口,重写接口方法
//如果指定的数与参数相等返回0;如果指定的数小于参数返回 -1;
//如果指定的数大于参数返回 1,执行交换,此时升序排序,倒序情况则相反。
@Override
public int compareTo(PlatFrom next) {
return next.getZ()-this.high;
}
}
static int leftUnder(int k) {//返回左端点下面的平台
for(int m=k+1;m<=N;m++) {
if(platfroms[m].Lx<=platfroms[k].Lx&&platfroms[k].Lx<=platfroms[m].Rx&&platfroms[k].high-platfroms[m].high<=MAX) {
return m;
}
}
return -1;
}
static int rightUnder(int k) {//返回右端点下面的平台
for(int m=k+1;m<=N;m++) {
if(platfroms[m].Lx<=platfroms[k].Rx&&platfroms[k].Rx<=platfroms[m].Rx&&platfroms[k].high-platfroms[m].high<=MAX) {
return m;
}
}
return -1;
}
}
这是我写的最久的代码!mmmp,2020.3.8 1:55我还是写出来了!