1. 程式人生 > >【BZOJ】1185: [HNOI2007]最小矩形覆蓋-旋轉卡殼

【BZOJ】1185: [HNOI2007]最小矩形覆蓋-旋轉卡殼

傳送門:bzoj1185


題解

洛谷上非常卡精度。

先求出凸包。

顯然最小矩形的某種方案是存在一條邊與凸包上的某條邊重合的(否則旋轉一下即可)。

所以列舉邊,旋轉卡殼求出對踵點,還有對應的最左最右點。


程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long double db;
const db eps=1e-10;
const int N=5e4+10;

int n,top,stk[N];db ans=1e233;

inline int dcmp(db x) {if
(fabs(x)<eps) return 0;return x<0?-1:1;} struct P{ db x,y; P(db _x=0,db _y=0):x(_x),y(_y){}; bool operator <(const P&ky)const{ if(dcmp(y-ky.y)==0) return dcmp(x-ky.x)<1; return dcmp(y-ky.y)<1; } db operator ^(const P&ky){return x*ky.y-y*ky.x;} db operator *(const
P&ky){return x*ky.x+y*ky.y;} P operator -(const P&ky){return P(x-ky.x,y-ky.y);} P operator *(const db&ky){return P(x*ky,y*ky);} P operator +(const P&ky){return P(x+ky.x,y+ky.y);} }p[N],t[N],mn,q[5]; inline db sqr(db x){return x*x;} inline db dist(P a,P b){return sqrt(sqr(a.x-b.x)
+sqr(a.y-b.y));} inline bool cmp(P a,P b) { int res=dcmp((a-mn)^(b-mn)); if(!res) return (dist(a,mn)<dist(b,mn)); return res==1; } inline bool onlf(P a,P b,P c){return dcmp((c-b)^(a-b))>-1;} inline void graham() { int i,j; for(i=2;i<=n;++i) if(t[i]<t[1]) swap(t[i],t[1]); stk[++top]=1;mn=t[1];sort(t+2,t+n+1,cmp); for(i=2;i<=n;++i){ for(;top>1 && onlf(t[stk[top]],t[stk[top-1]],t[i]);--top); stk[++top]=i; } } inline void sol() { int i,l=1,r=1,op=1;P dlt; for(i=1;i<=top;++i) p[i]=t[stk[i]]; p[0]=p[top];db L,R,D,H; for(i=0;i<top;++i){ D=dist(p[i],p[i+1]);dlt=p[i+1]-p[i]; for(;dcmp((dlt^(p[op+1]-p[i]))-(dlt^(p[op]-p[i])))>-1;op=(op+1)%top); for(;dcmp((dlt*(p[r+1]-p[i]))-(dlt*(p[r]-p[i])))>-1;r=(r+1)%top);if(!i) l=r; for(;dcmp((dlt*(p[l+1]-p[i]))-(dlt*(p[l]-p[i])))<1;l=(l+1)%top); L=(dlt*(p[l]-p[i]))/D;R=(dlt*(p[r]-p[i]))/D; H=fabs(dlt^(p[op]-p[i]))/D; if((R-L)*H<ans){ ans=(R-L)*H; q[0]=p[i]+(dlt*(R/D)); q[1]=q[0]+((p[r]-q[0])*(H/dist(p[r],q[0]))); q[2]=q[1]+((p[i]-q[0])*((R-L)/dist(p[i],q[0]))); q[3]=q[0]+(q[2]-q[1]); } } } inline double trs(db x){int res=dcmp(x);if(!res) return 0;return (double)x;} int main(){ int i,j=0;double a,b; scanf("%d",&n); for(i=1;i<=n;++i) {scanf("%lf%lf",&a,&b);t[i]=P((db)a,(db)b);} graham();sol(); for(i=1;i<4;++i) if(q[i]<q[j]) j=i; printf("%.5lf\n",trs(ans)); for(i=0;i<4;++i) printf("%.5lf %.5lf\n",trs(q[(j+i)%4].x),trs(q[(j+i)%4].y)); return 0; }

(算幾寫起來總是不太順手。。。