1. 程式人生 > >[POJ3301]Texas Trip(三分-最小正方形覆蓋)

[POJ3301]Texas Trip(三分-最小正方形覆蓋)

題目:

我是超連結

題解:

設正方形的邊都與座標軸平行可以求出來一個正方形
如果這個正方形旋轉一個角度的話正方形的大小可能會改變
經過我多年文化課做幾何旋轉題目,可以發現正方形的面積關於旋轉角度的函式單峰

如果面積隨角度變化是單峰的函式,那麼自然就可以想到是三分,按照題目要求求正方形最小的面積,如果正方形是平行於x軸的,那麼正方形面積是x的最大距離*y的最大的距離。然後旋轉正方形,在0到90度內總會找到一個正方形面積的最小值
但是旋轉正方形比較麻煩,我們可以考慮旋轉座標系,將座標系旋轉0~90度 ,按旋轉的角度重新計算各點的座標,然後找出x的差和y的差,計算面積。

因為是單峰的函式,所以用三分角度,找到一個最小的面積。
注意:三分的eps要很小,1e-12

角度旋轉公式x = x*cos(j) - y*sin(j) ; y = x*sin(j) + y*cos(j)

程式碼:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
double eps=1e-12;
const int N=50;
#define INF 1e9
const double pi=acos(-1.0);
struct po{double x,y;}a[N];
double maxx,maxy,minx,miny;int n;
double
bc(double j) { double x,y; maxx=maxy=-INF; minx=miny=INF; for (int i=1;i<=n;i++) { x=a[i].x*cos(j)-a[i].y*sin(j); y=a[i].x*sin(j)+a[i].y*cos(j); maxx=max(maxx,x); minx=min(minx,x); maxy=max(maxy,y); miny=min(miny,y); } return
max(maxx-minx,maxy-miny); } int main() { int T;scanf("%d",&T); while (T--) { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); double l=0,r=pi/2,m1,m2; while (r-l>=eps) { m1=l+(r-l)/3; m2=r-(r-l)/3; if (bc(m1)<bc(m2)) r=m2; else l=m1; } l=bc(l); printf("%.2lf\n",l*l); } }