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 }
转载于:https://www.cnblogs.com/dd-bond/p/11308219.html
HDU 6617 Enveloping Convex(凸包+半平面交+二分)相关推荐
- UVA1396 Most Distant Point from the Sea(AM - ICPC - Tokyo - 2007)(计算几何,半平面交 + 二分答案)
整理的算法模板合集: ACM模板 题目传送门 见<训练指南>P279 很明显就是一个二分答案,它问的是最远的点,直接枚举因为这里都是double类型的数所以有无限个点,我们可以直接二分. ...
- [模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和
一些基本的定义在这里: [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算 自适应Simpson Simpson's Rule: \[ \int ^b_a f(x)dx\approx ...
- [2019HDU多校第四场][HDU 6617][D. Enveloping Convex]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6617 题目大意:给出一凸包\(P\),求最小的与\(P\)相似且对应边平行的多边形,使得题目给出的\( ...
- Polygons HDU - 1632 (半平面交)
Polygons HDU - 1632 题意:求两个多边形的"异或"面积. 半平面交~ 1 #include <bits/stdc++.h> 2 using namespace std; ...
- [POJ3384]Feng Shui(半平面交+凸包)
题目: 我是超链接 题意: 在一个凸多边形中放两个半径固定的圆,要求输出使覆盖面积最大的(可重叠)两个圆圆心 题解: Emmm...套路缩小凸多边形,形成的凸包是圆心可以在的位置,然后暴力找最远点! ...
- LA 3890 (半平面交) Most Distant Point from the Sea
题意: 给出一个凸n边形,求多边形内部一点使得该点到边的最小距离最大. 分析: 最小值最大可以用二分. 多边形每条边的左边是一个半平面,将这n个半平面向左移动距离x,则将这个凸多边形缩小了.如果这n个 ...
- [凸多边形最大内切圆][半平面交]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 ...
- 模板:半平面交(计算几何)
所谓半平面交,就是和"半平先生"当面交谈.顾名思义,这是一个源于日本的算法. (逃) 前言 感觉应用很灵活的一个算法,一切有两个变量的线性规划问题都可以转化为半平面交. 有时可能要 ...
- Feng Shui POJ - 3384 [半平面交]
Feng Shui POJ - 3384 题意:n个顶点的凸包,放入2个半径为r的圆,可以重叠,要求面积最大,输出2个圆的圆心坐标(保留4位小数) 思路:找出圆心的可行域(内推r,求半平面交),再求核 ...
最新文章
- 几款高频环形磁芯的性能对比
- 人力资源计算机考试题库,人力资源考试题库.doc
- 常见采集脑电信号的四种技术
- java B2B2C Springboot电子商务平台源码-SSO单点登录之OAuth2.0登录认证
- php数组去重的函数,php数组去重的函数代码
- Web开发静态资源处理---SpringBoot
- python正则表达式处理txt_Python文本处理服务(re正则表达式例子)
- 移动开发解决方案之玩转输入框
- 十个人在一座荒岛上_如果您在荒岛上,您将携带哪个执照?
- windows 防火墙疑难解答程序_Win8系统设置允许程序通过防火墙的方法
- 国外量化投资的经典案例
- 解读SSD目标检测方法
- Mac环境下使用XMAPP 安装testlink
- 校学 离散数学主析取合取范式 做题心得
- Android面试之J2SE基础
- 请编程序将china译成密码,密码规律是:用原来的字母后面第4个字母代替原来的字母。例如:字母A后面4个字母为E,因此,China应译为Glmre。
- 计算方法--函数插值
- 华为鸿蒙几点开发布会,华为鸿蒙系统正式发布时间
- MySQL事务与锁详解,并发读异常与隔离策略
- SpringBoot 做系统的权限管理——
热门文章
- 关于Java中的finalize方法
- javascript如何监听 form.submit()事件
- 运放的输入共模区间及解决VICMR问题
- 又涨了!2021 年 5 月程序员工资统计新鲜出炉,网友:还是Java程序员牛逼~
- 冒泡算法的Java实现
- 2016年,上海的互联网企业是否值得加入?
- 操作系统之虚拟化CPU(一)介绍
- python查文献_自从用了Python,轻松查文献,释放80%的重复劳动时间
- XML中PCDATA与CDATA的区别
- TP5.1自定义创建命令(php think make:controller app\index\User)