HDU 6617 Enveloping Convex(凸包+半平面交+二分)

首先对于这m个点维护出一个凸包M,那么问题就变成了判断凸包P进行放大缩小能不能包含凸包M。(凸包P可以进行中心对称变换再进行放大缩小,见题意)

如何判断合适的相似比呢,我们可以用二分去放大缩小凸包P的坐标,得到最小的相似比。

接下来就是如何判断是否包含。我们需要对凸包P上的每一条向量,在凸包M上找到这么一个点,使得这个点左侧的所有凸包M上的点都在向量的左侧,那么我们可以直接同时逆时针枚举,用一个变量维护凸包M上的点,因为是同逆时针,凸包M上的点至少有一个只会被遍历一次,那么复杂度可以证明为On,这样就可以维护出来凸包P上的向量所对应的在凸包M上的点。因为包含关系,满足所有的向量的对应点都应该在向量的左侧,那么我们将这个向量相对于这个点的坐标求出来,然后维护一个半平面交是否有解即可,判断这个半平面交维护出来的是否是一个合法的凸包,当然由于我们是逆时针枚举的向量,需要先对凸包P进行逆时针转动,所以我们没必要将这些相对于坐标的向量排序,直接维护半平面交,但是最后我们需要判断维护出来的凸包是否严格按照逆时针旋转,因为位置是相对的,可能出现一个向下的向量的左侧是一个向上的向量,这样的关系是矛盾的。

注意细节,由于我的模板用的是求直线交点,精度比较差,eps开的比较小。

  1 //        ——By DD_BOND
  2 
  3 //#include<bits/stdc++.h>
  4 //#include<unordered_map>
  5 //#include<unordered_set>
  6 #include<functional>
  7 #include<algorithm>
  8 #include<iostream>
  9 //#include<ext/rope>
 10 #include<iomanip>
 11 #include<climits>
 12 #include<cstring>
 13 #include<cstdlib>
 14 #include<cstddef>
 15 #include<cstdio>
 16 #include<memory>
 17 #include<vector>
 18 #include<cctype>
 19 #include<string>
 20 #include<cmath>
 21 #include<queue>
 22 #include<deque>
 23 #include<ctime>
 24 #include<stack>
 25 #include<map>
 26 #include<set>
 27 
 28 #define fi first
 29 #define se second
 30 #define MP make_pair
 31 #define pb push_back
 32 
 33 #pragma GCC optimize(3)
 34 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
 35 
 36 typedef long long ll;
 37 
 38 using namespace std;
 39 
 40 const int MAXN=1e5+10;
 41 const double eps=1e-18;
 42 const double pi=acos(-1.0);
 43 const ll INF=0x3f3f3f3f3f3f3f3f;
 44 
 45 inline int dcmp(double x){
 46     if(fabs(x)<eps)    return 0;
 47     return (x>0? 1: -1);
 48 }
 49 
 50 inline double sqr(double x){ return x*x; }
 51 
 52 struct Point{
 53     double x,y;
 54     Point(){ x=0,y=0; }
 55     Point(double _x,double _y):x(_x),y(_y){}
 56     void input(){ scanf("%lf%lf",&x,&y); }
 57     void output(){ printf("%.2f %.2f\n",x,y); }
 58     bool operator <(const Point &b)const{
 59         return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
 60     }
 61     double operator ^(const Point &b)const{        //叉积
 62         return x*b.y-y*b.x;
 63     }
 64     double operator *(const Point &b)const{        //点积
 65         return x*b.x+y*b.y;
 66     }
 67     bool operator ==(const Point &b)const{
 68         return dcmp(x-b.x)==0&&dcmp(y-b.y)==0;
 69     }
 70     Point operator +(const Point &b)const{
 71         return Point(x+b.x,y+b.y);
 72     }
 73     Point operator -(const Point &b)const{
 74         return Point(x-b.x,y-b.y);
 75     }
 76     Point operator *(double a){
 77         return Point(x*a,y*a);
 78     }
 79     Point operator /(double a){
 80         return Point(x/a,y/a);
 81     }
 82     double len2(){    //长度平方
 83         return sqr(x)+sqr(y);
 84     }
 85     double len(){   //长度
 86         return sqrt(len2());
 87     }
 88 };
 89 
 90 inline double cross(Point a,Point b){    //叉积
 91     return a.x*b.y-a.y*b.x;
 92 }
 93 
 94 inline double dot(Point a,Point b){    //点积
 95     return a.x*b.x+a.y*b.y;
 96 }
 97 
 98 struct Line{
 99     Point s,e;
100     Line(){}
101     Line(Point _s,Point _e):s(_s),e(_e){}
102     Point operator &(const Line &b)const{     //求两直线交点
103         Point res=s;
104         double t=((s-b.s)^(b.s-b.e))/(((s-e)^(b.s-b.e))+eps);
105         res.x+=(e.x-s.x)*t;
106         res.y+=(e.y-s.y)*t;
107         return res;
108     }
109 };
110 
111 int relation(Point p,Line l){    //点和向量关系   1:左侧   2:右侧   3:在线上
112     int c=dcmp(cross(p-l.s,l.e-l.s));
113     if(c<0)    return 1;
114     else if(c>0)    return 2;
115     else    return 3;
116 }
117 
118 bool counter_wise(Point *p,int n){            //多边形点集调整为逆时针顺序
119     for(int i=1;i<n-1;i++)
120         if(dcmp(cross(p[i]-p[i-1],p[i+1]-p[i-1]))>0)    return 0;
121         else if(dcmp(cross(p[i]-p[i-1],p[i+1]-p[i-1]))<0){
122             reverse(p,p+n);
123             return 1;
124         }
125     return 1;
126 }
127 
128 Point tmp[MAXN];
129 int convex_hull(Point *p,int n,Point *ch){    //求凸包
130     int m=0;
131     sort(p,p+n);
132     for(int i=0;i<n;i++){
133         while(m>1&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<=0)    m--;
134         tmp[m++]=p[i];
135     }
136     int k=m;
137     for(int i=n-2;i>=0;i--){
138         while(m>k&&dcmp(cross(tmp[m-1]-tmp[m-2],p[i]-tmp[m-1]))<=0)    m--;
139         tmp[m++]=p[i];
140     }
141     if(n>1)    m--;
142     for(int i=0;i<m;i++)    ch[i]=tmp[i];
143     return m;
144 }
145 
146 Line que[MAXN];
147 int half_plane_intersection(Line *L,int n){    //以逆时针方向 半平面交求多边形的核  ch表示凸包的顶点  返回顶点数 -1则表示不存在
148     int head=0,tail=1;
149     que[0]=L[0],que[1]=L[1];
150     for(int i=2;i<n;i++){
151         while(tail>head&&relation(que[tail]&que[tail-1],L[i])==2)   tail--;
152         while(tail>head&&relation(que[head]&que[head+1],L[i])==2)   head++;
153         que[++tail]=L[i];
154     }
155     while(tail>head&&relation(que[tail]&que[tail-1],que[head])==2)  tail--;
156     while(tail>head&&relation(que[head]&que[head+1],que[tail])==2)  head++;
157     for(int i=head;i<=tail;i++){
158         int j=(i==tail? head: i+1);
159         if(dcmp(cross(que[i].e-que[i].s,que[j].e-que[j].s))<=0)
160             return 0;
161     }
162     return 1;
163 }
164 
165 Line line[MAXN];
166 Point p[MAXN],q[MAXN],ops[MAXN];
167 
168 int main(void){
169     int T;  scanf("%d",&T);
170     while(T--){
171         int n;  scanf("%d",&n);
172         for(int i=0;i<n;i++)    p[i].input();
173         int m;  scanf("%d",&m);
174         for(int i=0;i<m;i++)    q[i].input();
175         counter_wise(p,n);  m=convex_hull(q,m,q);
176         double ans=INF;
177         for(int t=1;t<=2;t++){
178             for(int i=0;i<n;i++)    p[i]=Point(-p[i].x,-p[i].y);
179             for(int i=0,j=0;i<n;i++){
180                 while(dcmp(cross(p[(i+1)%n]-p[i],q[(j-1+m)%m]-q[j]))<0||dcmp(cross(p[(i+1)%n]-p[i],q[(j+1)%m]-q[j]))<0)   j=(j+1)%m;
181                 ops[i]=q[j];
182             }
183             double l=0,r=1e10;
184             for(int i=0;i<70;i++){
185                 double mid=(l+r)/2;
186                 for(int j=0;j<n;j++)    line[j]=Line(p[j]*mid-ops[j],p[(j+1)%n]*mid-ops[j]);
187                 if(half_plane_intersection(line,n)) r=mid;
188                 else    l=mid;
189             }
190             ans=min(ans,l);
191         }
192         printf("%.10lf\n",ans);
193     }
194     return 0;
195 }

猜你喜欢

转载自www.cnblogs.com/dd-bond/p/11308219.html