1. 程式人生 > >[BZOJ1185][HNOI2007]最小矩形覆蓋-[凸包+旋轉卡殼]

[BZOJ1185][HNOI2007]最小矩形覆蓋-[凸包+旋轉卡殼]

col %d pac .com desc ret math n) abs

Description

傳送門

Solution

感性理解一下,最小矩形一定是由一條邊和凸包上的邊重合的。

然後它就是模板題了。。然而真的好難調,小於大於動不動就打錯。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-9;
int n;
struct node{double x,y;
    friend node 
operator +(node a,node b){return node{a.x+b.x,a.y+b.y};} friend node operator -(node a,node b){return node{a.x-b.x,a.y-b.y};} friend double operator *(node a,node b){return a.x*b.y-a.y*b.x;} friend double operator /(node a,node b){return a.x*b.x+a.y*b.y;} friend node operator *(node a,double
b) {return node{a.x*b,a.y*b};} friend bool operator <(node a,node b) { return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y;} }p[50010],st[50010],low; double dis(node a){return a.x*a.x+a.y*a.y;} bool cmp(node a,node b){ double t=(a-p[1])*(b-p[1]); if (fabs(t)<eps) return dis(a-p[1])<dis(b-p[1
]); return t>0; } int top=0,now; int main() { scanf("%d",&n); low.x=low.y=2147483647; scanf("%lf%lf",&p[1].x,&p[1].y); for (int i=2;i<=n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); if (p[i]<p[1]) swap(p[i],p[1]); } sort(p+2,p+n+1,cmp); st[++top]=p[1]; for (int i=2;i<=n;i++) { while (top>1&&(st[top]-st[top-1])*(p[i]-st[top])<eps) top--; st[++top]=p[i]; } st[0]=st[top]; node pr[4]; double L,R,D,H,ans=1e10;int l=1,r=1,now=1; for (int i=0;i<top;i++) { D=sqrt(dis(st[i]-st[i+1])); while ((st[i+1]-st[i])*(st[now+1]-st[i])>(st[i+1]-st[i])*(st[now]-st[i])-eps) now=(now+1)%top; while ((st[i+1]-st[i])/(st[r+1]-st[i])>(st[i+1]-st[i])/(st[r]-st[i])-eps) r=(r+1)%top; if (!i) l=r; while ((st[i+1]-st[i])/(st[l+1]-st[i])<(st[i+1]-st[i])/(st[l]-st[i])+eps) l=(l+1)%top; L=(st[i+1]-st[i])/(st[l]-st[i])/D;R=(st[i+1]-st[i])/(st[r]-st[i])/D; H=abs((st[i+1]-st[i])*(st[now]-st[i])/D); if ((R-L)*H<ans) { ans=(R-L)*H; pr[0]=st[i]+(st[i+1]-st[i])*(R/D); pr[1]=pr[0]+(st[r]-pr[0])*(H/sqrt(dis(pr[0]-st[r]))); pr[2]=pr[1]-(pr[0]-st[i])*((R-L)/sqrt(dis(st[i]-pr[0]))); pr[3]=pr[2]-(pr[1]-pr[0]); } } now=0; for (int i=1;i<=3;i++) if (pr[i]<pr[now]) now=i; printf("%.5f\n",ans); for (int i=0;i<=3;i++) { if (pr[(i+now)%4].x>-5*1e-6) pr[(i+now)%4].x=fabs(pr[(i+now)%4].x); if (pr[(i+now)%4].y>-5*1e-6) pr[(i+now)%4].y=fabs(pr[(i+now)%4].y); printf("%.5f %.5f\n",pr[(i+now)%4].x,pr[(i+now)%4].y); } }

[BZOJ1185][HNOI2007]最小矩形覆蓋-[凸包+旋轉卡殼]