首先对于这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 }

转载于:https://www.cnblogs.com/dd-bond/p/11308219.html

HDU 6617 Enveloping Convex(凸包+半平面交+二分)相关推荐

  1. UVA1396 Most Distant Point from the Sea(AM - ICPC - Tokyo - 2007)(计算几何,半平面交 + 二分答案)

    整理的算法模板合集: ACM模板 题目传送门 见<训练指南>P279 很明显就是一个二分答案,它问的是最远的点,直接枚举因为这里都是double类型的数所以有无限个点,我们可以直接二分. ...

  2. [模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和

    一些基本的定义在这里: [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算 自适应Simpson Simpson's Rule: \[ \int ^b_a f(x)dx\approx ...

  3. [2019HDU多校第四场][HDU 6617][D. Enveloping Convex]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6617 题目大意:给出一凸包\(P\),求最小的与\(P\)相似且对应边平行的多边形,使得题目给出的\( ...

  4. Polygons HDU - 1632 (半平面交)

    Polygons HDU - 1632 题意:求两个多边形的"异或"面积. 半平面交~ 1 #include <bits/stdc++.h> 2 using namespace std; ...

  5. [POJ3384]Feng Shui(半平面交+凸包)

    题目: 我是超链接 题意: 在一个凸多边形中放两个半径固定的圆,要求输出使覆盖面积最大的(可重叠)两个圆圆心 题解: Emmm...套路缩小凸多边形,形成的凸包是圆心可以在的位置,然后暴力找最远点! ...

  6. LA 3890 (半平面交) Most Distant Point from the Sea

    题意: 给出一个凸n边形,求多边形内部一点使得该点到边的最小距离最大. 分析: 最小值最大可以用二分. 多边形每条边的左边是一个半平面,将这n个半平面向左移动距离x,则将这个凸多边形缩小了.如果这n个 ...

  7. [凸多边形最大内切圆][半平面交]Most Distant Point from the Sea POJ3525

    The main land of Japan called Honshu is an island surrounded by the sea. In such an island, it is na ...

  8. 模板:半平面交(计算几何)

    所谓半平面交,就是和"半平先生"当面交谈.顾名思义,这是一个源于日本的算法. (逃) 前言 感觉应用很灵活的一个算法,一切有两个变量的线性规划问题都可以转化为半平面交. 有时可能要 ...

  9. Feng Shui POJ - 3384 [半平面交]

    Feng Shui POJ - 3384 题意:n个顶点的凸包,放入2个半径为r的圆,可以重叠,要求面积最大,输出2个圆的圆心坐标(保留4位小数) 思路:找出圆心的可行域(内推r,求半平面交),再求核 ...

最新文章

  1. 几款高频环形磁芯的性能对比
  2. 人力资源计算机考试题库,人力资源考试题库.doc
  3. 常见采集脑电信号的四种技术
  4. java B2B2C Springboot电子商务平台源码-SSO单点登录之OAuth2.0登录认证
  5. php数组去重的函数,php数组去重的函数代码
  6. Web开发静态资源处理---SpringBoot
  7. python正则表达式处理txt_Python文本处理服务(re正则表达式例子)
  8. 移动开发解决方案之玩转输入框
  9. 十个人在一座荒岛上_如果您在荒岛上,您将携带哪个执照?
  10. windows 防火墙疑难解答程序_Win8系统设置允许程序通过防火墙的方法
  11. 国外量化投资的经典案例
  12. 解读SSD目标检测方法
  13. Mac环境下使用XMAPP 安装testlink
  14. 校学 离散数学主析取合取范式 做题心得
  15. Android面试之J2SE基础
  16. 请编程序将china译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。例如:字母A后面4个字母为E,因此,China应译为Glmre。
  17. 计算方法--函数插值
  18. 华为鸿蒙几点开发布会,华为鸿蒙系统正式发布时间
  19. MySQL事务与锁详解,并发读异常与隔离策略
  20. SpringBoot 做系统的权限管理——

热门文章

  1. 关于Java中的finalize方法
  2. javascript如何监听 form.submit()事件
  3. 运放的输入共模区间及解决VICMR问题
  4. 又涨了!2021 年 5 月程序员工资统计新鲜出炉,网友:还是Java程序员牛逼~
  5. 冒泡算法的Java实现
  6. 2016年,上海的互联网企业是否值得加入?
  7. 操作系统之虚拟化CPU(一)介绍
  8. python查文献_自从用了Python,轻松查文献,释放80%的重复劳动时间
  9. XML中PCDATA与CDATA的区别
  10. TP5.1自定义创建命令(php think make:controller app\index\User)