2020年第十一届蓝桥杯决赛JAVA B G题“画廊“

7 篇文章 0 订阅
4 篇文章 0 订阅

2020年第十一届蓝桥杯决赛JAVA B H题"画廊"

2020国赛 JAVA B组 个人题解目录
试题 H: 画廊
时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
小蓝办了一个画展,在一个画廊左右两边陈列了他自己的作品。为了使画
展更有意思,小蓝没有等距陈列自己的作品,而是按照更有艺术感的方式陈列。
在画廊的左边陈列了 L 幅作品,在画廊的右边陈列了 R 幅作品,左边的作品距
离画廊的起点依次为 u 1 , u 2 , ···, u L ,右边的作品距离画廊起点依次为 v 1 , v 2 , ···,
v R 。
每周,小蓝要整理一遍自己的每一幅作品。整理一幅作品的时间是固定的,
但是要带着沉重的工具。从一幅作品到另一幅作品之间的距离为直线段的长度。
小蓝从画廊的起点的正中央(左右两边的中点)出发,整理好每一幅画,
最终到达画廊的终点的正中央。已知画廊的宽为 w。
请问小蓝最少带着工具走多长的距离?
【输入格式】
输入的第一行包含四个整数 L, R, d, w,表示画廊左边和右边的作品数量,
以及画廊的长度和宽度。
第二行包含 L 个正整数 u 1 , u 2 , ···, u L ,表示画廊左边的作品的位置。
第三行包含 R 个正整数 v 1 , v 2 , ···, v R ,表示画廊右边的作品的位置。
【输出格式】
输出一个实数,四舍五入保留两位小数,表示小蓝最少带着工具走的距离。
【样例输入】
3 3 10 2
1 3 8
2 4 6

【样例输出】
14.71
【样例说明】
小蓝从起点开始,首先到达左边第一幅作品(走动距离
√ 2),然后到达左
边第二幅作品(走动距离 2),然后到达右边第一幅作品(走动距离
√ 5),然后
到达右边第二幅和第三幅作品(走动距离 2 和 2),然后到达左边第三幅作品
(走动距离 2
√ 2),最后到达画廊终点(走动距离 √ 5)。
总共距离为
√ 2 + 2 + √ 5 + 2 + 2 + 2 √ 2 + √ 5 ≈ 14.71。
【评测用例规模与约定】
对于 40% 的评测用例,1 ≤ L,R ≤ 10, 1 ≤ d ≤ 100, 1 ≤ w ≤ 100。
对于 70% 的评测用例,1 ≤ L,R ≤ 100, 1 ≤ d ≤ 1000, 1 ≤ w ≤ 1000。
对于所有评测用例,1 ≤ L,R ≤ 500, 1 ≤ d ≤ 100000, 1 ≤ w ≤ 100000,
0 ≤ u 1 < u 2 < ··· < u L ≤ d, 0 ≤ v 1 < v 2 < ··· < v R ≤ d。

解析:动态规划
思路:dp[i][j][k] 其中表示当前左边从下往上整理到了第i幅画,j表示当前右边当前整理到了第j幅画,k表示人当前在左边还是右边,0表示左边,1表示右边,dp[i][j][k]表示整理了左边前i幅画和右边前j幅画后人在左/右时需要走的最小距离。
(1)初始化:
dp[1][0][0]为起点到左边第一幅画的距离;
dp[0][1][1]为起点到右边第一幅画的距离;
dp[i][0][0] = dp[i-1][0][0] + 左边i-1到i的距离;
dp[0][j][1] = dp[0][j-1][1] + 右边j-1到j的距离;
(2)递推:
中间的每一步只会来自同一边的上一副画和对边的某幅画即:
dp[i][j][0] = min(dp[i-1][j][0]+左边i-1到i的距离 , dp[i-1][j][1]+右边j到左边i的距离);
dp[i][j][1] = min(dp[i][j-1][1]+右边j-1到j的距离 , dp[i][j-1][0]+左边i到右边j的距离);
(3)结论:
最终结果=min(dp[max i ][max j][0]+左边最后一副画到终点的距离,dp[max i ][max j][1]+右边最后一副画到终点的距离)


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class H {

	public static void main(String[] args) throws IOException {
		StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));//数据量很大,需要高效输
		in.nextToken();
		int L = (int)in.nval;
		in.nextToken();
		int R = (int)in.nval;
		in.nextToken();
		double d = (double)in.nval;
		in.nextToken();
		double w = (double)in.nval;
		
		double sx = w/2 , sy = 0 , ex = w/2 , ey = d;//起点终点坐标
		
		
		double[][][] dp = new double[L+1][R+1][2];
		point[] Lp = new point[L+1];
		point[] Rp = new point[R+1];
		
		for(int i=1;i<=L;i++) {
			in.nextToken();
			int y = (int)in.nval;
			Lp[i] = new point(0, y);
		}
		Lp[0] = new point(-99999999, -99999999) ;
		
		
		for(int i=1;i<=R;i++) {
			in.nextToken();
			int y = (int)in.nval;
			Rp[i] = new point(w, y);
		}
		Rp[0] = new point(-99999999, -99999999) ;

		for(int i=1;i<=L;i++) 
			for(int j=1;j<=R;j++) 
				for(int k=0;k<=1;k++) dp[i][j][k]=99999999;
		 
		
		dp[1][0][0] = cal(Lp[1].x,Lp[1].y,sx,sy);
		dp[0][1][1] = cal(Rp[1].x,Rp[1].y,sx,sy);
		dp[1][1][0] = dp[0][1][1] + cal(Lp[1].x, Lp[1].y, Rp[1].x,Rp[1].y); 
		dp[1][1][1] = dp[1][0][0] + cal(Lp[1].x, Lp[1].y, Rp[1].x,Rp[1].y); 
		
		for(int i=2;i<=L;i++) dp[i][0][0] = dp[i-1][0][0]+Lp[i].y-Lp[i-1].y;
		for(int i=2;i<=R;i++) dp[0][i][1] = dp[0][i-1][1]+Rp[i].y-Rp[i-1].y;
		
		for(int i=1;i<=L;i++) {
			for(int j=1;j<=R;j++) {
				for(int k=1;k>=0;k--) {
					if(i==1&&j==1)break;
					if(k==0)dp[i][j][0] = Math.min(dp[i-1][j][0]+Lp[i].y-Lp[i-1].y, dp[i-1][j][1]+cal(Lp[i].x, Lp[i].y,Rp[j].x, Rp[j].y));
					if(k==1)dp[i][j][1] = Math.min(dp[i][j-1][1]+Rp[j].y-Rp[j-1].y, dp[i][j-1][0]+cal(Lp[i].x, Lp[i].y,Rp[j].x, Rp[j].y));
				}	
			}
		}

		
		System.out.printf("%.2f",Math.min(dp[L][R][0]+cal(Lp[L].x, Lp[L].y, ex, ey), dp[L][R][1]+cal(Rp[R].x, Rp[R].y, ex, ey)));
	}

	private static double cal(double x1, double y1, double x2, double y2) {//计算距离
		double t1 = Math.pow(x1-x2,2);
		double t2 = Math.pow(y1-y2,2);
		return Math.sqrt(t1+t2);
	}

}

class point{
	double x;
	double y;
	public point(double x,double y) {
		this.x=x;
		this.y=y;
	}
}
  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值