POJ 3301 Texas Trip (三分)

Texas Trip

给出平面上一些点(坐标),让我们在平面上选择一个正方形能够覆盖这些所有的点,求这个正方形的最小面积。

我们很容易找到一个符合要求的正方形,也就是所有边都平行于坐标轴的正方形,那么我们就只找平行于坐标轴的正方形,我们将每个点都旋转一定的角度,他们的相对位置不变,而正方形却相对于点在旋转,面积在改变,那么就可以找到最小的正方形.

我们只需要考虑最优的旋转角度.

假设旋转的角度为f,初始点的坐标为(x,y)与x轴的夹角为a,距离坐标原点的长度为len,那么x = cos(a)*len,y = sin(a)*len,nx = cos(a+f)*len,ny = sin(a+f)*len

拆开nx = cos(a)*cos(f)*len-sin(a)*sin(f)*len,ny = sin(a)*cos(f)*len+cos(a)*sin(f)*len

也就是说 nx = cos(f)*x-sin(f)*y,ny = sin(f)*x+cos(f)*y;

正方形的边长等于max(rightx-leftx,upy-downy) = max(cos(f)*(x1-x2)-sin(f)*(y1-y2),sin(f)*(x1-x2)+cos(f)*(y1-y2))(x1>x2 &&  y1>y2)

等于 max(sqrt((x1-x2)^2+(y1-y2)^2)sin(f+p1),sqrt((x1-x2)^2+(y1-y2)^2)sin(f+p2))

那么边长是由K*sin(f+p)转化而来的,那么在这个函数上一定存在一个角度使得边长最小,还有一个很显然的就是旋转角度在180°之内根据对称一定会找到最优解,那么f+p就在(-0.5*pi,pi)之间那么就是一个单峰函数,那么就可以三分角度了。

不知道为什么交G++就WA了,交C++就A了。。。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const double pi = acos(-1.0);
const double eps = 1e-8;
const int maxn = 510;
const double inf = 0xfffffff;
struct node{
	double x,y;
}p[maxn];
int n,T;
node rotate(node p,double k){
	node a;
	a.x = p.x*cos(k)-p.y*sin(k);
	a.y = p.x*sin(k)+p.y*cos(k);
	return a;
}

double calc(double k){
	double minx = inf,miny = inf;
	double maxx = -inf,maxy = -inf;
	for(int i = 1;i <= n;++i){
		node np;
		np = rotate(p[i],k);
		minx = min(minx,np.x),miny = min(miny,np.y);
		maxx = max(maxx,np.x),maxy = max(maxy,np.y);
	}
	return max(maxx-minx,maxy-miny);
}


int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		memset(p,0,sizeof(p));
		for(int i = 1;i <= n;++i){
			scanf("%lf%lf",&p[i].x,&p[i].y);
		}
		double l = 0.0,r = pi,mid,rmid;
		while (l + eps < r) {
			mid = (l+r)/2;
			rmid = (mid+r)/2;
			if(calc(mid) < calc(rmid)) r = rmid;
			else l = mid;
		}
		double len = calc(l);
		printf("%.2lf
",len*len);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/xgtao984/p/5720227.html