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; }