2019牛客暑期多校训练营(第十场)G——Road Construction(思维+计算几何)

链接:https://ac.nowcoder.com/acm/contest/890/G
来源:牛客网
 

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 524288K,其他语言1048576K
Special Judge, 64bit IO Format: %lld

题目描述

The mayor of Byteland is planning to build a new road across the town. Constructing new roads may facilitate transportation and stimulate economic development; the negative aspects include, the noise that may affect the residents nearby, and the nonnegligible impacts on the local ecological environment.

You have been required to draft a road construction plan. In your plan, you can model the residents of the town as points, and the road as a straight line of infinite length. Your plan should satisfy the following conditions:
- The road should not pass through any resident of the city;
- The numbers of residents on both sides of the road are equal;
- The minimum of the distances of the residents to the road is maximized.

The following figure depicts the optimal road construction plan for the first sample test data.

Since there are too many residents in Byteland, you believe it is impossible to find such a construction plan manually. It's your time to write a program and find the optimal plan.

输入描述:

The input starts with a line containing an even integer n (1≤n≤300)(1 \leq n \leq 300)(1≤n≤300) indicating the number of residents in Byteland. It is then followed by n lines, each containing two integers x, y (∣x∣,∣y∣≤106)(|x|, |y| \leq 10^6)(∣x∣,∣y∣≤106), the Cartesian coordinates of a resident. No two residents share the same coordinates.

输出描述:

Print the minimum of the distances of the residents to the road you plan to build. Your answer should have an absolute or relative error of no more than 10−610^{-6}10−6.

示例1

输入

复制

6
0 0
3 0
1 2
4 3
-1 4
5 -3

输出

复制

1.264911064067

示例2

输入

复制

2
1 3
2 5

输出

复制

1.118033988750

题意:找一条线让所有点平均分布在它的两侧,不能再线上,然后求出距离最近的点的最大值;

题解:

1.最优的直线一定平行或垂直于两个点的连线(显然)

2.枚举最优直线斜率(最多有n^2个),然后用kth-element找到以这条直线排序的中间两个点(用截距排序),找到之后求出两条线的距离,答案就是距离/2

上个图看一下:

上代码:

#include <bits/stdc++.h>
using namespace std;
const int MAX = 520;
double x[MAX],y[MAX],b[MAX];
double maxx;
int n;
void solve(double k){
	for (int i = 0; i < n;i++) b[i]=y[i]-k*x[i];//求截距
	nth_element(b,b+n/2,b+n);//找中间右边那个,下面的" *max_element(b,b+n/2) " 是找中间左边那个
	double w=(b[n/2]-*max_element(b,b+n/2))/sqrt(1+k*k);//求距离(右减左,就是大减小)
	maxx=max(maxx,w/2);//均分保证最大
}
int main(){
	scanf("%d",&n);
	for (int i = 0; i < n;i++) scanf("%lf%lf",&x[i],&y[i]);
	for (int i = 0; i < n;i++){
		for (int j = i+1; j < n;j++){
			double k = (y[i]-y[j])/(x[i]-x[j]);
			solve(k);//平行
			solve(-1.0/k);//垂直
		}
	}
	printf("%.12f\n",maxx);
	return 0;
} 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心脏dance

如果解决了您的疑惑,谢谢打赏呦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值