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

Posted dd-bond

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 

 

以上是关于HDU 6617 Enveloping Convex(凸包+半平面交+二分)的主要内容,如果未能解决你的问题,请参考以下文章

P6617 查找 Search 线段树 查找区间内是否有两个和为w的数(w不变)

没有键为“Conve”的“IEnumerable”类型的 ViewData 项

REACT ELEVATION

Java密码学XML签名

Run 一个容器

Android Studio打包以及Gradle配置构建