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

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

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

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

 //        ——By DD_BOND

 //#include<bits/stdc++.h>
//#include<unordered_map>
//#include<unordered_set>
#include<functional>
#include<algorithm>
#include<iostream>
//#include<ext/rope>
#include<iomanip>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<cstddef>
#include<cstdio>
#include<memory>
#include<vector>
#include<cctype>
#include<string>
#include<cmath>
#include<queue>
#include<deque>
#include<ctime>
#include<stack>
#include<map>
#include<set> #define fi first
#define se second
#define MP make_pair
#define pb push_back #pragma GCC optimize(3)
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") typedef long long ll; using namespace std; const int MAXN=1e5+;
const double eps=1e-;
const double pi=acos(-1.0);
const ll INF=0x3f3f3f3f3f3f3f3f; inline int dcmp(double x){
if(fabs(x)<eps) return ;
return (x>? : -);
} inline double sqr(double x){ return x*x; } struct Point{
double x,y;
Point(){ x=,y=; }
Point(double _x,double _y):x(_x),y(_y){}
void input(){ scanf("%lf%lf",&x,&y); }
void output(){ printf("%.2f %.2f\n",x,y); }
bool operator <(const Point &b)const{
return (dcmp(x-b.x)==? dcmp(y-b.y)< : x<b.x);
}
double operator ^(const Point &b)const{ //叉积
return x*b.y-y*b.x;
}
double operator *(const Point &b)const{ //点积
return x*b.x+y*b.y;
}
bool operator ==(const Point &b)const{
return dcmp(x-b.x)==&&dcmp(y-b.y)==;
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator *(double a){
return Point(x*a,y*a);
}
Point operator /(double a){
return Point(x/a,y/a);
}
double len2(){ //长度平方
return sqr(x)+sqr(y);
}
double len(){ //长度
return sqrt(len2());
}
}; inline double cross(Point a,Point b){ //叉积
return a.x*b.y-a.y*b.x;
} inline double dot(Point a,Point b){ //点积
return a.x*b.x+a.y*b.y;
} struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e):s(_s),e(_e){}
Point operator &(const Line &b)const{ //求两直线交点
Point res=s;
double t=((s-b.s)^(b.s-b.e))/(((s-e)^(b.s-b.e))+eps);
res.x+=(e.x-s.x)*t;
res.y+=(e.y-s.y)*t;
return res;
}
}; int relation(Point p,Line l){ //点和向量关系 1:左侧 2:右侧 3:在线上
int c=dcmp(cross(p-l.s,l.e-l.s));
if(c<) return ;
else if(c>) return ;
else return ;
} bool counter_wise(Point *p,int n){ //多边形点集调整为逆时针顺序
for(int i=;i<n-;i++)
if(dcmp(cross(p[i]-p[i-],p[i+]-p[i-]))>) return ;
else if(dcmp(cross(p[i]-p[i-],p[i+]-p[i-]))<){
reverse(p,p+n);
return ;
}
return ;
} Point tmp[MAXN];
int convex_hull(Point *p,int n,Point *ch){ //求凸包
int m=;
sort(p,p+n);
for(int i=;i<n;i++){
while(m>&&dcmp(cross(tmp[m-]-tmp[m-],p[i]-tmp[m-]))<=) m--;
tmp[m++]=p[i];
}
int k=m;
for(int i=n-;i>=;i--){
while(m>k&&dcmp(cross(tmp[m-]-tmp[m-],p[i]-tmp[m-]))<=) m--;
tmp[m++]=p[i];
}
if(n>) m--;
for(int i=;i<m;i++) ch[i]=tmp[i];
return m;
} Line que[MAXN];
int half_plane_intersection(Line *L,int n){ //以逆时针方向 半平面交求多边形的核 ch表示凸包的顶点 返回顶点数 -1则表示不存在
int head=,tail=;
que[]=L[],que[]=L[];
for(int i=;i<n;i++){
while(tail>head&&relation(que[tail]&que[tail-],L[i])==) tail--;
while(tail>head&&relation(que[head]&que[head+],L[i])==) head++;
que[++tail]=L[i];
}
while(tail>head&&relation(que[tail]&que[tail-],que[head])==) tail--;
while(tail>head&&relation(que[head]&que[head+],que[tail])==) head++;
for(int i=head;i<=tail;i++){
int j=(i==tail? head: i+);
if(dcmp(cross(que[i].e-que[i].s,que[j].e-que[j].s))<=)
return ;
}
return ;
} Line line[MAXN];
Point p[MAXN],q[MAXN],ops[MAXN]; int main(void){
int T; scanf("%d",&T);
while(T--){
int n; scanf("%d",&n);
for(int i=;i<n;i++) p[i].input();
int m; scanf("%d",&m);
for(int i=;i<m;i++) q[i].input();
counter_wise(p,n); m=convex_hull(q,m,q);
double ans=INF;
for(int t=;t<=;t++){
for(int i=;i<n;i++) p[i]=Point(-p[i].x,-p[i].y);
for(int i=,j=;i<n;i++){
while(dcmp(cross(p[(i+)%n]-p[i],q[(j-+m)%m]-q[j]))<||dcmp(cross(p[(i+)%n]-p[i],q[(j+)%m]-q[j]))<) j=(j+)%m;
ops[i]=q[j];
}
double l=,r=1e10;
for(int i=;i<;i++){
double mid=(l+r)/;
for(int j=;j<n;j++) line[j]=Line(p[j]*mid-ops[j],p[(j+)%n]*mid-ops[j]);
if(half_plane_intersection(line,n)) r=mid;
else l=mid;
}
ans=min(ans,l);
}
printf("%.10lf\n",ans);
}
return ;
}

HDU 6617 Enveloping Convex(凸包+半平面交+二分)的更多相关文章

  1. HDU 3761 炸碉堡【半平面交(nlogn)】+【二分】

    <题目链接> <   转载于   > 题目大意: 给出一个凸多边形,顶点为一些防御塔,保护范围是凸多形内部,不包括边界,在多边形内部选择一点,使得对方至少需要摧毁的塔防数量最多 ...

  2. POJ 3525 Most Distant Point from the Sea [半平面交 二分]

    Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5153   ...

  3. 简单几何(半平面交+二分) LA 3890 Most Distant Point from the Sea

    题目传送门 题意:凸多边形的小岛在海里,问岛上的点到海最远的距离. 分析:训练指南P279,二分答案,然后整个多边形往内部收缩,如果半平面交非空,那么这些点构成半平面,存在满足的点. /******* ...

  4. POJ 3525 Most Distant Point from the Sea (半平面交+二分)

    Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3476   ...

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

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

  6. POJ 3525 半平面交+二分

    二分所能形成圆的最大距离,然后将每一条边都向内推进这个距离,最后所有边组合在一起判断时候存在内部点 #include <cstdio> #include <cstring> # ...

  7. UVA 3890 Most Distant Point from the Sea(二分法+半平面交)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11358 [思路] 二分法+半平面交 二分与海边的的距离,由法向量可 ...

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

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

  9. UVa 1475 (二分+半平面交) Jungle Outpost

    题意: 有n个瞭望塔构成一个凸n边形,敌人会炸毁一些瞭望台,剩下的瞭望台构成新的凸包.在凸多边形内部选择一个点作为总部,使得敌人需要炸毁的瞭望塔最多才能使总部暴露出来.输出敌人需要炸毁的数目. 分析: ...

随机推荐

  1. Node Buffer 利用 slice + indexOf 生成 split 方法

    demo let buf = Buffer.from('你你我们我你们'); Buffer.prototype.split = function (seq) { let arr=[]; let len ...

  2. sql中的group_concat用法

    group_concat(),手册上说明:该函数返回带有来自一个组的连接的非NULL值的字符串结果.比较抽象,难以理解. 通俗点理解,其实是这样的:group_concat()会计算哪些行属于同一组, ...

  3. vue-cli项目中引入全局scss

    加载一个全局设置文件 在每个组件里加载一个设置文件,而无需每次都将其显式导入,是一个常见的需求.比如为所有组件全局使用 scss 变量.为了达成此目的: npm install sass-resour ...

  4. A1042

    洗牌,共洗k次,每次将将原先的牌洗进输入好的位置. 步骤: 1 设置次数k,输入位置数列next[55],填充初始牌序start[55]: 2 end[next[i]]=start[i]把新的牌序赋值 ...

  5. linux运维、架构之路-Hadoop完全分布式集群搭建

    一.介绍 Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS.HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件 ...

  6. 在 centos7.5 使用 DockerFile 构建镜像时报错 "Error parsing reference:"microsoft/dotnet:2.2-aspnetcore-runtime AS base"is not a valid repository/tag: invalid reference format"

    运行 dockerfile 时报出的错误 FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base Error parsing reference: & ...

  7. PHP培训教程 PHP里10个鲜为人知但却非常有用的函数

    php里有非常丰富的内置函数,很多我们都用过,但仍有很多的函数我们大部分人都不熟悉,可它们却十分的有用.这篇文章里,兄弟连小编列举了一些鲜为人知但会让你眼睛一亮的PHP函数. levenshtein( ...

  8. Linux常用命令学习记录

    兄弟连Linux培训 ,小编整理了常用的Linux学习命令: 1 cp 拷贝命令 参数:-p 文件属性一起拷贝 -r 拷贝文件夹 -d 软链信息等一起拷贝 -a 是-rdp的简写 2 find 文件查 ...

  9. .Net手动实现ORM及代码生自动成器

    序言 代码生成器 同时提供便捷的开发管理功能和多项开发工作中常用到的辅助工具功能,您可以很方便轻松地进行项目开发,让软件开发变得轻松而快乐!帮您快速开发项目,缩短开发周期,减少开发成本,大大提高了企业 ...

  10. [ZJU 1002] Fire Net

    ZOJ Problem Set - 1002 Fire Net Time Limit: 2 Seconds      Memory Limit: 65536 KB Suppose that we ha ...