zoukankan      html  css  js  c++  java
  • 【动态规划】POJ1661 Help Jimmy

    Help Jimmy

    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 11621   Accepted: 3827

    Description

    "Help Jimmy" 是在下图所示的场景上完成的游戏。 

    场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。 

    Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束。 

    设计一个程序,计算Jimmy到底地面时可能的最早时间。 

    Input

    第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是四个整数N,X,Y,MAX,用空格分隔。N是平台的数目(不包括地面),X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。接下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1 <= N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1..N)。所有坐标的单位都是米。 

    Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保证问题一定有解。 

    Output

    对输入的每组测试数据,输出一个整数,Jimmy到底地面时可能的最早时间。

    Sample Input

    1
    3 8 17 20
    0 10 8
    0 10 13
    4 14 3

    Sample Output

    23

    Source

     
    试题分析:设状态dp[i][0]为第i块木板左边落下的最小时间
                          dp[i][1]为第i块木板右边落下的最小时间
                   那么容易得出转移方程

                       dp[i][0]=min(dp[i][0],dp[j][0]+abs(a[j].X1-a[i].X1)+a[i].H-a[j].H);
                       dp[i][0]=min(dp[i][0],dp[j][1]+abs(a[j].X2-a[i].X1)+a[i].H-a[j].H);

                       dp[i][1]=min(dp[i][1],dp[j][0]+abs(a[j].X1-a[i].X2)+a[i].H-a[j].H);
                       dp[i][1]=min(dp[i][1],dp[j][1]+abs(a[j].X2-a[i].X2)+a[i].H-a[j].H);

                   当然,前提是j块木板的高度差不能超过MAX且第i块木板落下到第j块木板(这个可以预处理)

                   这个题要倒着做!倒着做!

                   开始正着做了一遍,把discuss中的数据测光了也是对的,莫名其妙WA了一小时 TAT

                   后来花了10分钟重写了一个正着做的就一遍AC了……

                   此题需要注意的细节:

                             ①MEMSET inf

                             ②落到板子的边缘也算落在板子上

                             ③在高度允许情况下可以直接落到地上

                             ④abs

                    是否感觉有些反人类思维呢?听说最短路可以过TAT

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<algorithm>
    //#include<cmath>
    
    using namespace std;
    const int INF = 9999999;
    #define LL long long
    
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    int N,X,Y,MAX;
    int T;
    struct data{
    	int X1,X2,H;
    }a[1001];
    int dp[1001][2];
    int down[1001][2];
    int fir;
    bool flag=false;
    
    bool cmp(data a,data b){
        return a.H>b.H;
    }
    
    void pre(){//预处理
    	sort(a+1,a+N+1,cmp);//sort一定要加
    	bool flag1=false,flag2=false;
    	for(int i=1;i<=N;i++){//记录第i块板子左/右落下会落到哪里
    		flag1=false,flag2=false;
    		for(int j=i+1;j<=N;j++){
    			if(flag1&&flag2) break;
    			if(a[i].H>a[j].H){
    				if(a[j].X1<=a[i].X1&&a[j].X2>=a[i].X1&&!flag1) down[i][0]=j,flag1=true;
    				if(a[j].X2>=a[i].X2&&a[j].X1<=a[i].X2&&!flag2) down[i][1]=j,flag2=true; 
    			}
    		} 
    		if(!flag1) down[i][0]=N+1;//N+1板子为地面
    		if(!flag2) down[i][1]=N+1;
    	}
    	a[N+1].H=0;a[N+1].X1=-INF,a[N+1].X2=INF;
    	for(int i=1;i<=N+1;i++){//预处理从初始点落下会落到哪里
    		if(Y-a[i].H<=MAX)
    		    if(a[i].X1<=X&&a[i].X2>=X){
    		        fir=i;
    		        break;
    		    } 
    	}
        if(fir==N+1){
    		printf("%d
    ",Y);//可以直接落到地面上,直接输出
    		flag=true;
    	}
    	return ;
    }
    
    int main(){
    	T=read();
    	while(T--){
    		flag=false;
    	    N=read(),X=read(),Y=read(),MAX=read();
            for(int i=1;i<=N;i++){
            	a[i].X1=read();
            	a[i].X2=read();
            	a[i].H=read();
    		}
    		memset(dp,INF,sizeof(dp));//memset
    		pre();
    		if(flag) continue;
    		dp[N+1][0]=0;
    		dp[N+1][1]=0;
    		dp[N][1]=dp[N][0]=a[N].H;
    		for(int i=N-1;i>=fir;i--){
    			for(int j=i+1;j<=N+1;j++){
    				if(abs(a[i].H-a[j].H)>MAX) break;//如果高度差已经大于MAX直接退出
    				if(down[i][0]==j){//dp
    					if(j!=N+1){
    				        dp[i][0]=min(dp[i][0],dp[j][0]+abs(a[j].X1-a[i].X1)+a[i].H-a[j].H);
    				        dp[i][0]=min(dp[i][0],dp[j][1]+abs(a[j].X2-a[i].X1)+a[i].H-a[j].H);
    				    }
    				    else dp[i][0]=min(dp[i][0],a[i].H);
    				}
    				if(down[i][1]==j){
    					if(j!=N+1){
    				        dp[i][1]=min(dp[i][1],dp[j][0]+abs(a[j].X1-a[i].X2)+a[i].H-a[j].H);
    				        dp[i][1]=min(dp[i][1],dp[j][1]+abs(a[j].X2-a[i].X2)+a[i].H-a[j].H);
    				    }
    				    else dp[i][1]=min(dp[i][1],a[i].H); 
    			    }
    			}
    		}
    		printf("%d
    ",min(dp[fir][0]+abs(a[fir].X1-X)+abs(Y-a[fir].H),dp[fir][1]+abs(a[fir].X2-X)+abs(Y-a[fir].H)));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    分布式锁没那么难,手把手教你实现 Redis 分布锁!|保姆级教程
    我去,这么简单的条件表达式竟然也有这么多坑
    MySQL 可重复读,差点就让我背上了一个 P0 事故!
    用了这么多年的 Java 泛型,你对它到底有多了解?
    项目一再跳票?试试这一招:用Deadline倒逼生产力
    Code Review最佳实践
    你的大学会有模拟面试吗?一些常见面试问题背后的逻辑是什么?
    从软件工程的角度解读任正非的新年公开信
    记在美国的一次校园招聘
    为什么软件工程教科书上的内容和现实的软件项目之间存在着一定差异?
  • 原文地址:https://www.cnblogs.com/wxjor/p/6955857.html
Copyright © 2011-2022 走看看