备战Noip2018模拟赛15(A组) T2 Column 淘淘的柱子朋友

10月17日备战Noip2018模拟赛15(A组)

T2 Column淘淘的柱子朋友

题目描述

明天就是noip了,淘淘家来了很多柱子朋友,他们有粗有细,但都躺在淘淘家不动,这叫淘淘很是不爽,因为他需要空间来思考人生。但是他又不好意思把朋友们赶走,也不想把它们摞起来,于是他来想你求助。

你需要解决这样一个问题,地上从左到右平行地倒放了n根柱子,各自有一个半径ri,你需要用两个板子从两边向中间推,将柱子们尽量地向中间压起来,但是不能让柱子离地。请告诉淘淘柱子的最少占地范围,即两个板子之间最小距离。

输入格式

第一行为柱子数n
第二行包含n个整数r1,r2,...,rn1≤ri≤100)代表从左到右柱子的半径。

输出格式

输出一行一个保留三位的小数,表示答案。

输入样例

2  
4 12

输出样例

29.856

数据范围

对于10%的数据,n≤5;

对于60%的数据,n≤100;

对于100%的数据,n≤1000。


思路

DP

EMM ......这竟然是一道纯数学题,  死算

既然要距离最小,那么每个柱子一定要与左右的柱子或者板子相切

两个圆之间的水平r_ {1} + r_ {2} + AH距离为,如下图所示

除此之外还有一种特殊情况,有一个半径很小的圆柱被夹在两个直径较大的圆柱中间,如下图所示

这样我们就应该直接取更大的值

状态设计: dp [i]表示从第一个圆柱到第i个圆柱的距离

状态转移:dp [i] = dp [j] + r_ {i} -r_j + \ sqrt {\ left(r_i + r_j \ right)^ {2} + \ left(r_i  -  r_j \ right)^ {2}}

初始化:dp [i] = r [i] * 2

复杂度:\ theta \ left(n ^ {2} \ right)

代码

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int N = 1001;
const double eps = 1e-12;

int n;
double ans, h;
double r[N], d[N];

int main ()
{
	freopen ("column.in", "r", stdin);
	freopen ("column.out", "w", stdout);
	
	scanf ("%d", & n);
	for (int i = 1; i <= n; i ++){
		scanf ("%lf", & r[i]);
	}
	
	for (int i = 1; i <= n ; i ++){
		d[i] = r[i] * 2;
		for (int j = 1; j < i; j ++){
			h = 2 * sqrt (r[i] * r[j]);
			if (d[i] + eps < d[j] - r[j] + r[i]+ h)
				d[i] = d[j] - r[j] + r[i] + h;
		}
		if (ans + eps < d[i]) ans = d[i];
	}
	
	printf ("%.3lf", ans);
	
	fclose (stdin);
	fclose (stdout);
	return 0;
}

上文思路中出现的图片由cx大佬提供,再次感谢,顺便orz

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值