POJ 3301 (坐标变换、三分枚举计算 点集最小正方形覆盖)

Texas Trip

Description

After a day trip with his friend Dick, Harry noticed a strange pattern of tiny holes in the door of his SUV. The local American Tire store sells fiberglass patching material only in square sheets. What is the smallest patch that Harry needs to fix his door?

Assume that the holes are points on the integer lattice in the plane. Your job is to find the area of the smallest square that will cover all the holes.

Input

The first line of input contains a single integerT expressed in decimal with no leading zeroes, denoting the number of test cases to follow. The subsequent lines of input describe the test cases.

Each test case begins with a single line, containing a single integern expressed in decimal with no leading zeroes, the number of points to follow; each of the followingn lines contains two integersx and y, both expressed in decimal with no leading zeroes, giving the coordinates of one of your points.

You are guaranteed that T ≤ 30 and that no data set contains more than 30 points. All points in each data set will be no more than 500 units away from (0,0).

Output

Print, on a single line with two decimal places of precision, the area of the smallest square containing all of your points.

Sample Input

2
4
-1 -1
1 -1
1 1
-1 1
4
10 1
10 -1
-10 1
-10 -1

Sample Output

4.00
242.00


思路

题目要求计算覆盖所有离散在二维空间内的点最小正方形的面积

1.一开始我的想法是覆盖所有点嘛,就枚举所有点两两之间的距离,然后以最大的距离作为正方形的边。但这种方法不是最小的,一个反证就是两点放在一个正方形的对角线上,这时候正方形的面积小于以距离为边的正方形的面积。要是以最大距离/根号2作为边呢?那样有些点就会覆盖不到。

2.进一步思考的话,之所以出现结果与想法1之间矛盾的原因在于:想法1求解的方式只考虑了两点之间的直线距离,但是在二维空间下,覆盖所有点的最小正方形应该由“x方向距离”和“y方向之间距离”的同时来决定的,而能够影响这两个坐标轴距离长短的因素就在于我们如何将这些点投影到二维坐标系中。

3.将n各点投影到二维坐标系中,我们可以以任意点为基点,对所有点进行旋转,考虑到我们主要求解的是最小面积,则在[0,180]与[180,360]之间可以看做是对称的,由此将整个问题转换成将所有点投影到二维坐标系中,枚举角度的问题,具体的枚举方式采用三分法(这里边长关于角度为单峰函数,求导可证明)


坐标转换公式

x: x*cos(angle)-y*sin(angle)
y: x*sin(angle)+y*cos(angle)

转换后有 X^2+Y^2=x^2+y^2

三分模板

double calculate(type a)
{
	//根据题目进行计算 
}

void solve(void)
{
	double left,right;
	double mid,midmid;
	double mid_value,midmid_value;
	left=MIN;
	right=MAX;
	while(right-left>eps)
	{
		mid=(left+right)/2;
		midmid=(mid+right)/2;
		mid_value=calculate(mid);
		midmid_value=calculate(midmid);
		if(mid_value>=midmid_value) left=mid;//以极小值为例 
		else right=midmid;
	}
	//处理结果left(或right) 
}


代码示例

#include<iostream>
#include<math.h>
#include<algorithm>
#include<cstdio>
using namespace std;

const int maxn=35;
const double eps=1e-8;
const double pi=acos(-1.0);//注意π的表示方法 
const int inf=0x3f3f3f3f;

struct node{
	double x,y;
}p[maxn];

int n;

double filter(double angle){
	double maxx=-inf,minx=inf,maxy=-inf,miny=inf;//初始化最大最小值 
	for(int i=0;i<n;++i){
		maxx=max(maxx,p[i].x*cos(angle)-p[i].y*sin(angle));
		maxy=max(maxy,p[i].x*sin(angle)+p[i].y*cos(angle));
		miny=min(miny,p[i].x*sin(angle)+p[i].y*cos(angle));
		minx=min(minx,p[i].x*cos(angle)-p[i].y*sin(angle));
	}
	return max(maxx-minx,maxy-miny);
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=0;i<n;++i){
			scanf("%lf%lf",&p[i].x,&p[i].y);
		}
		double l=0.0,r=pi,mid,midmid;
		while(r-l>eps){
			mid=(r+l)/2.0;
			midmid=(r+mid)/2.0;
			if(filter(mid)>filter(midmid)) l=mid;
			else r=midmid;
		}
		double ans=filter(l);
		printf("%.2f\n",ans*ans);
	}
	return 0;	
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值