码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 1185 旋转卡壳 最小矩形覆盖

时间:2015-07-11 16:20:23      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:

题目大意 就是求一个最小矩形覆盖,逆时针输出其上面的点

这里可以看出,那个最小的矩形覆盖必然有一条边经过其中凸包上的两个点,另外三条边必然至少经过其中一个点,而这样的每一个点逆时针走一遍都满足单调性

所以可以利用旋转卡壳的思想找到这样的三个点

以每一条边作为基础,循环n次得到n个这样的矩形,找到其中面积最小的即可

然后自己画画图,作出矩形对应的两条边的单位向量,那么这四个点就非常好求了

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 using namespace std;
  7 #define N 50010
  8 #define eps 1e-9
  9 const double PI = acos(-1.0);
 10 int n , top;
 11 
 12 int dcmp(double x)
 13 {
 14     if(fabs(x)<eps) return 0;
 15     return x<0?-1:1;
 16 }
 17 
 18 struct Point{
 19     double x , y;
 20     Point(double x=0 , double y=0):x(x),y(y){}
 21     void input(){scanf("%lf%lf" , &x , &y);}
 22     void output(){printf("%.5f %.5f\n" , x , y);}
 23     bool operator<(const Point &m)const{
 24         return x<m.x||(x==m.x&&y<m.y);
 25     }
 26 }po[N] , rec[N] , p[4];
 27 
 28 typedef Point Vector;
 29 
 30 Vector operator+(Vector a , Vector b){return Vector(a.x+b.x , a.y+b.y);}
 31 Vector operator-(Vector a , Vector b){return Vector(a.x-b.x , a.y-b.y);}
 32 Vector operator*(Vector a , double b){return Vector(a.x*b , a.y*b);}
 33 Vector operator/(Vector a , double b){return Vector(a.x/b , a.y/b);}
 34 double operator*(Vector a , Vector b){return a.x*b.y-a.y*b.x;}
 35 
 36 double Dot(Vector a , Vector b){return a.x*b.x+a.y*b.y;}
 37 double Len(Vector a){return sqrt(Dot(a,a));}
 38 int Polxy()
 39 {
 40     sort(po , po+n);
 41     rec[0]=po[0] , rec[1]=po[1];
 42     top=2;
 43     for(int i=2 ; i<n ; i++){
 44         while(top>=2&&(rec[top-1]-rec[top-2])*(po[i]-rec[top-2])<=0)
 45             top--;
 46         rec[top++] = po[i];
 47     }
 48     int tmp=top;
 49     for(int i=n-2 ; i>=0 ; i--){
 50         while(top>=tmp&&(rec[top-1]-rec[top-2])*(po[i]-rec[top-2])<=0)
 51             top--;
 52         rec[top++] = po[i];
 53     }
 54     top--;
 55     return top;
 56 }
 57 
 58 Vector Normal(Vector a)
 59 {
 60     double l = Len(a);
 61     return Vector(-a.y/l , a.x/l);
 62 }
 63 
 64 double calCalip()
 65 {
 66   //  for(int i=0 ; i<top ; i++) rec[i].output();
 67     Point ch[2];
 68     ch[0] = rec[0] , ch[1] = rec[1];
 69     int i1=0 , i2=0 , i3=0;
 70     double maxn = 1e18;
 71     ch[0] = rec[0] , ch[1] = rec[1];
 72     while(dcmp(fabs((rec[(i1+1)%top]-ch[0])*(ch[1]-ch[0]))-fabs((rec[i1]-ch[0])*(ch[1]-ch[0])))>=0) i1=(i1+1)%top;
 73     while(dcmp(Dot(rec[(i2+1)%top]-ch[0] , ch[1]-ch[0])-Dot(rec[i2]-ch[0] , ch[1]-ch[0]))>=0) i2=(i2+1)%top;
 74     while(dcmp(Dot(rec[(i3-1+top)%top]-ch[1] , ch[0]-ch[1])-Dot(rec[i3]-ch[1] , ch[0]-ch[1]))>=0) i3=(i3-1+top)%top;
 75     for(int i=0 ; i<top ; i++){
 76         ch[0] = rec[i] , ch[1] = rec[(i+1)%top];
 77         while(dcmp(fabs((rec[(i1+1)%top]-ch[0])*(ch[1]-ch[0]))-fabs((rec[i1]-ch[0])*(ch[1]-ch[0])))>=0) i1=(i1+1)%top;
 78         while(dcmp(Dot(rec[(i2+1)%top]-ch[0] , ch[1]-ch[0])-Dot(rec[i2]-ch[0] , ch[1]-ch[0]))>=0) i2=(i2+1)%top;
 79         while(dcmp(Dot(rec[(i3+1)%top]-ch[1] , ch[0]-ch[1])-Dot(rec[i3]-ch[1] , ch[0]-ch[1]))>=0) i3=(i3+1)%top;
 80         double l = Len(ch[1]-ch[0]);
 81         double h = fabs((rec[i1]-ch[0])*(ch[1]-ch[0]))/l;
 82         double len1 = Dot(rec[i2]-ch[1] , ch[1]-ch[0])/l; //右侧长度
 83         double len2 = Dot(rec[i3]-ch[0] , ch[0]-ch[1])/l; //左侧长度
 84         double suml = l+len1+len2;
 85        // cout<<i<<" "<<l<<" "<<h<<" "<<len1<<" "<<len2<<" "<<suml*h<<endl;
 86         if(dcmp(suml*h-maxn)<0){
 87             Vector unit1 = (ch[1]-ch[0])/l;
 88             Vector unit2 = Normal(unit1);
 89             maxn = suml*h;
 90             p[0] = ch[1]+unit1*len1;
 91             p[1] = p[0]+unit2*h;
 92             p[2] = p[1]-unit1*suml;
 93             p[3] = p[2]-unit2*h;
 94         }
 95     }
 96     return maxn;
 97 }
 98 
 99 int main()
100 {
101    // freopen("in.txt" , "r" , stdin);
102     while(scanf("%d" , &n)!=EOF)
103     {
104         for(int i=0 ; i<n ; i++) po[i].input();
105         Polxy();
106         double ret = calCalip();
107         printf("%.5f\n" , ret);
108         int st = 0;
109         for(int i=1 ; i<4 ; i++){
110             if(p[i].y<p[st].y || (p[i].y==p[st].y&&p[i].x<p[st].x)) st = i;
111         }
112         for(int i=0;i<4;i++){
113             p[st].output();
114             st = (st+1)%4;
115         }
116     }
117     return 0;
118 }

 

bzoj 1185 旋转卡壳 最小矩形覆盖

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/4638694.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!