1. 程式人生 > >Poj 3301 Texas Trip (三分搜尋)

Poj 3301 Texas Trip (三分搜尋)

題目連結:http://poj.org/problem?id=3301

題意:求最小的正方形面積保證正方形可以覆蓋所有給出的點。

思路參考自:http://hi.baidu.com/answerme11/item/597255a690ac76dc5af19152

網上偶然看到的演算法,第一道三分搜尋的題,鑑於坑爹的百度,我把思路複製貼上一下……

我無法證明問題函式的凹凸性質,但是感覺上問題是有這種性質的,可以用三分法求極值來解決。

問題是要求最小的正方形,假設這個正方形的邊都是分別與座標軸平行,也就是說正方形沒有旋轉一定的角度,那麼我們只要考慮最上,最下,最左,最右 的點即可,當正方形旋轉過一定的角度d後,我們也只要考慮最邊上的點的距離差即可(故這題也可用列舉旋轉角度的方法來求解,但要注意步長的選取以保證精度)。

   假設旋轉角度為d,那麼列舉每兩個點關於旋轉角度為d的直線距離取最大值,即可保證覆蓋所有的點,在兩個方向上這樣的距離分別為:

   dis1 = fabs(cos(d) * (y[i] - y[j]) - sin(d) * (x[i] - x[j]))

   dis2 = fabs(sin(d) * (y[i] - y[j]) + cos(d) * (x[i] - x[j]))

   以上式子很好推導,自己畫出座標系,分析即可。

  當然dis1和dis2大小不一定一致,要保證圖形是覆蓋所有點的正方形,所以我們選取較大者為邊長。

  在提交過程中發現解決這題三分方式的不同對精度要求不同:

  double mid1 = (left + right)/2;             

  double mid2 = (mid1 + right)/2;         

相比 

   double mid1 =left +(right - left)/3;
   double mid2 = right - (right - left)/3;
   要求更高的精度。

#include <cstdio>
#include <cmath>
#define max(x,y) (x)>(y)?(x):(y)  
#define min(x,y) (x)<(y)?(x):(y)  

const int INF=0x6fffffff;
const double PI=acos(-1.0);
const double STD=1e-8;

struct Point
{
	double x,y;
}p[35];

int n;

double Cal (double alpha)
{
	double xmax,xmin,ymax,ymin,x,y;
	xmax=ymax=-INF;
	xmin=ymin=INF;
	for (int i=0;i<n;i++)
	{
		x=cos(alpha)*p[i].x-sin(alpha)*p[i].y;
		y=sin(alpha)*p[i].x+cos(alpha)*p[i].y;
		xmax=max(xmax,x);
		xmin=min(xmin,x);
		ymax=max(ymax,y);
		ymin=min(ymin,y);
	}
	double lenth=max(xmax-xmin,ymax-ymin);
	return lenth;
}

double Deal ()
{
	double low=0,high=0.5*PI,mid,midmid;
	while (fabs(high-low) > STD)
	{
		mid=(high+low)/2;
		midmid=(mid+high)/2;
		if (Cal(mid) <= Cal(midmid))
			high=midmid;
		else
			low=mid;
	}
	return pow(Cal(mid),2.0);
}

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);
		printf("%.2lf\n",Deal ());
	}
	return 0;
}