Bzoj1185 [HNOI2007]最小矩形覆盖

Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge
Submit: 1653  Solved: 745
[Submit][Status][Discuss]

Description

 

Input

 

Output

 

Sample Input

 

Sample Output

 

HINT

 

Source

 

数学问题 计算几何 旋转卡壳

按顺序枚举凸包上每一条边为底边,旋转卡壳找出此时的矩形的顶点、最左点和最右点,花式计算出边长,求面积,记录面积最小值和对应的解。

式子都能看懂,但不看题解就是写不出来,沮丧。

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 using namespace std;
  9 const int INF=0x3f3f3f3f;
 10 const double eps=1e-8;
 11 const int mxn=100010;
 12 int read(){
 13     int x=0,f=1;char ch=getchar();
 14     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 15     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 16     return x*f;
 17 }
 18 inline int DT(double x){
 19     if(abs(x)<eps)return 0;
 20     else return x<0?-1:1;
 21 }
 22 struct point{
 23     double x,y;
 24     point operator + (point b){return (point){x+b.x,y+b.y};}
 25     point operator - (point b){return (point){x-b.x,y-b.y};}
 26     point operator * (double v){return (point){x*v,y*v};}
 27     point operator / (double v){return (point){x/v,y/v};}
 28     bool operator < (point b)const{
 29         return x<b.x || (x==b.x && y<b.y);
 30     }
 31 }a[mxn],p[mxn],ans[5];
 32 typedef point Vector;
 33 double dot (point a,point b){return a.x*b.x+a.y*b.y;}
 34 double Cross(point a,point b){
 35     return a.x*b.y-a.y*b.x;
 36 }
 37 double dist(point a,point b){
 38     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 39 }
 40 double Len(point a){
 41     return sqrt((a.x*a.x)+(a.y*a.y));
 42 }
 43 double DLC(point p,point a,point b){
 44     Vector v1=p-a,v2=b-a;
 45     return fabs(Cross(v1,v2)/Len(v2));
 46 }
 47 int n;
 48 double ANS=0;
 49 int st[mxn],top=0,t2=0;
 50 void Andrew(){
 51     sort(p+1,p+n+1);
 52     for(int i=1;i<=n;i++){
 53         while(top>1 && Cross(p[st[top]]-p[st[top-1]],p[i]-p[st[top-1]])<=0)top--;
 54         st[++top]=i;
 55     }
 56     t2=top;
 57     for(int i=n-1;i;i--){
 58         while(t2>top && Cross(p[st[t2]]-p[st[t2-1]],p[i]-p[st[t2-1]])<=0)t2--;
 59         st[++t2]=i;
 60     }
 61     if(n>1)t2--;
 62     n=t2;
 63     for(int i=1;i<=n;i++){
 64         a[i]=p[st[i]];
 65     }
 66     return;
 67 }
 68 void solve(){
 69     ANS=(double)INF;
 70     a[n+1]=a[1];
 71     int l=1,r=1,tmp=1;
 72     double H,D,L,R;
 73     for(int i=1;i<=n;i++){
 74         while(DT(DLC(a[tmp],a[i],a[i+1])-DLC(a[tmp+1],a[i],a[i+1]))<=0)tmp=tmp%n+1;//顶部 
 75         while(DT(dot(a[i+1]-a[i],a[l]-a[i])-dot(a[i+1]-a[i],a[l+1]-a[i]))<=0)l=l%n+1;//左边 
 76         if(i==1)r=tmp;
 77         while(DT(dot(a[i+1]-a[i],a[r]-a[i])-dot(a[i+1]-a[i],a[r+1]-a[i]))>=0)r=r%n+1;//右边 
 78 //      printf("i:%d l:%d tmp:%d r:%d\n",i,l,tmp,r);
 79         L=dist(a[i+1],a[i]);
 80 //      H=fabs(Cross(a[tmp]-a[i],a[i+1]-a[i]))/L;//
 81         H=DLC(a[tmp],a[i],a[i+1]);
 82         D=fabs(dot(a[i+1]-a[i],a[l]-a[i])/L)+fabs(dot(a[i+1]-a[i],a[r]-a[i])/L);//底边长 
 83         R=H*D;
 84 //      printf("L:%.3f H:%.3f D:%.3f R:%.3f\n",L,H,D,R);
 85         if(R<ANS){//更新答案 
 86             ANS=R;
 87             Vector v=(a[i+1]-a[i])/L;//单位长度
 88             Vector u=(point){-v.y,v.x};//v逆时针转90度 
 89             ans[1]=a[i]+v*dot(a[r]-a[i],v);
 90             ans[2]=a[i]+v*dot(a[l]-a[i],v);
 91             ans[3]=ans[2]+u*H;
 92             ans[4]=ans[1]+u*H;
 93         }
 94     }
 95     return;
 96 }
 97 int main(){
 98 //  freopen("in.txt","r",stdin);
 99     int i,j;
100     scanf("%d",&n);
101     for(i=1;i<=n;i++){
102         scanf("%lf%lf",&p[i].x,&p[i].y);
103     }
104     Andrew();
105 /*  printf("n:%d\n",n);
106     for(i=1;i<=n;i++){
107         printf("%.3f  %.3f\n",a[i].x,a[i].y);
108     }*/
109     solve();
110     int pos=1;
111     for(i=1;i<=4;i++){
112         if(ans[i].y<eps)ans[i].y=0;
113         if(ans[i].x<eps)ans[i].x=0;
114         if(ans[i].y<ans[pos].y || (ans[i].y==ans[pos].y && ans[i].x<ans[pos].x))pos=i;
115     }
116     if(ANS<eps)ANS=0;
117     printf("%.5f\n",ANS);
118     for(i=pos;i<=4;i++)
119         printf("%.5f %.5f\n",ans[i].x,ans[i].y);
120     for(i=1;i<pos;i++)
121         printf("%.5f %.5f\n",ans[i].x,ans[i].y);
122     return 0;
123 }

 

posted @ 2017-04-09 21:36  SilverNebula  阅读(246)  评论(0编辑  收藏  举报
AmazingCounters.com