题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6617

题目大意:给出一凸包\(P\),求最小的与\(P\)相似且对应边平行的多边形,使得题目给出的\(m\)个点\(q_i\)都被该多边形包含在内,输出最小相似比

题解:二分答案\(k\),考虑如何判断\(P\)被放大\(k\)倍后是否可以通过平移这\(m\)个点使他们都在多边形内。将多边形的所有边看成有向线段(逆时针),则\(m\)个点都在多边形内当且仅当他们都在这些有向线段的左侧。对第\(i\)条边记录\(f_i\)表示如果点\(q_{f_i}\)在这条边左侧,就能保证所有点都在其左侧,通过对这\(m\)个点求凸包后可以在\(O(m)\)的时间复杂度内求出\(f_i\)。这样我们就只需要知道,是否存在一个平移的向量,使得这\(m\)个点平移之后,所有的点\(q_{f_i}\)都在第\(i\)条边的左侧。

   于是我们如果对每条边\((p_i,p_{i+1})\),求出了符合条件的向量集\(\vec{A_i}\),就可以通过判断他们的交集是否为空来判断当前的比例\(k\)是否合法。可以发现\(\vec{A_i}=\{\vec{OA}|A\text{ is on the left of }\vec{(p_i-q_{f_i},p_{i+1}-q_{f_i})}\}\)代表了一个半平面,这时我们就可以通过求半平面交来解决这道题了。

   注意题目的要求是对应边平行,因此我们还要把原图形旋转\(180^{\circ}\)再做一遍,取两次答案的最小值输出。

#include<bits/stdc++.h>
using namespace std;
#define N 100001
const double eps=1e-;
int sgn(double x)
{
if(x<-eps)return -;
if(x>eps)return ;
return ;
}
struct Point
{
double x,y;
void read(){scanf("%lf%lf",&x,&y);}
Point operator +(const Point &t)const{return {x+t.x,y+t.y};}
Point operator -(const Point &t)const{return {x-t.x,y-t.y};}
double operator *(const Point &t)const{return x*t.y-y*t.x;}
Point operator *(const double t)const{return {x*t,y*t};}
Point operator /(const double t)const{return {x/t,y/t};}
double ang()const{return atan2(1.0*y,1.0*x);}
double length()const{return sqrt(x*x+y*y);}
}p[N];
struct Line
{
Point p1,p2;
Point isct(const Line &t)const
{
double a=(p2-p1)*(t.p1-p1);
double b=(p2-p1)*(p1-t.p2);
return (t.p1*b+t.p2*a)/(a+b);
}
}q[N],line[N];
Point cent;
bool cmpang(const Point &p1,const Point &p2)
{
int tmp=sgn((p1-cent).ang()-(p2-cent).ang());
if(tmp!=)return tmp<;
return (p1-cent).length()<(p2-cent).length();
}
struct Polygon
{
int n;
Point a[N];
void read()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
a[i].read();
}
void ChangetoConvex()
{
for(int i=;i<=n;i++)
if(a[i].x<a[].x || (a[i].x==a[].x && a[i].y<a[].y))
swap(a[],a[i]);
cent=a[];
sort(a+,a+n+,cmpang);
int top=;
for(int i=;i<=n;i++)
{
while(top>= && (a[top]-a[top-])*(a[i]-a[top])<=)top--;
a[++top]=a[i];
}
n=top;
}
}P,Q;
int T,nxt[N],pre[N],f[N];
bool check(int i,Point A,Point B)
{
return sgn((B-A)*(Q.a[pre[i]]-Q.a[i]))>= && sgn((B-A)*(Q.a[nxt[i]]-Q.a[i]))>=;
}
bool Left(const Point &p,const Line &l){return sgn((l.p2-l.p1)*(p-l.p1))==;}
bool HalfPlane(int n)
{
int h=,t=;
q[]=line[];
for(int i=;i<=n;i++)
{
while(h<t && !Left(p[t-],line[i]))t--;
while(h<t && !Left(p[h],line[i]))h++;
if(sgn((q[t].p2-q[t].p1)*(line[i].p2-line[i].p1))==)
q[t]=Left(q[t].p1,line[i])?q[t]:line[i];
else q[++t]=line[i];
if(h<t)p[t-]=q[t].isct(q[t-]);
}
while(h<t && !Left(p[t-],q[h]))t--;
if(t-h<=)return false;
p[t]=q[t].isct(q[h]);
double ans=;
for(int i=h;i<=t;i++)
ans+=p[i]*p[(i+-h)%(t-h+)+h];
return sgn(ans)>=;
}
bool check(double k)
{
for(int i=;i<=P.n;i++)
line[i]={P.a[i]*k-Q.a[f[i]],P.a[i%P.n+]*k-Q.a[f[i]]};
return HalfPlane(P.n);
}
double solve()
{
int j=;
for(int i=;i<=P.n;i++)
{
while(!check(j,P.a[i],P.a[i%P.n+]))j=nxt[j];
f[i]=j;
}
double l=,r=1e9,mid;
while(l+eps<r)
{
mid=(l+r)*0.5;
if(check(mid))r=mid;
else l=mid;
}
return l;
}
void init()
{
double ans=1e18;
P.read(),Q.read();
if(Q.n==){printf("%.6f\n",0.0);return;}
P.ChangetoConvex();
Q.ChangetoConvex();
for(int i=;i<=Q.n;i++)
nxt[i]=i%Q.n+,pre[i%Q.n+]=i;
ans=min(ans,solve());
for(int i=;i<=P.n;i++)
P.a[i]=P.a[i]*(-1.0);
ans=min(ans,solve());
printf("%.6f\n",ans);
}
int main()
{
scanf("%d",&T);
while(T--)init();
}

   关于\(\vec{A_i}\)的说明:设点\(q_{f_i}\)为\(Q\),则\(\vec{OA}\)满足原点\(O\)在平移\(\vec{OA}\)后,他在有向线段\(\vec{(p_i-Q,p_{i+1}-Q)}\)的左侧。所以原点\(O\)在平移\(\vec{OA}\)后,再平移\(\vec{OQ}\),就能满足其在有向线段\(\vec{(p_i,p_{i+1})}\)的左侧。而\(O+\vec{OA}+\vec{OQ}=O+\vec{OQ}+\vec{OA}=Q+\vec{OA}\),因此将\(Q\)平移\(\vec{OA}\)是能满足要求的。

[2019HDU多校第四场][HDU 6617][D. Enveloping Convex]的更多相关文章

  1. [2019HDU多校第五场][HDU 6626][C. geometric problem]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6626 题目大意:给出平面上六个点\(A,B,M,N,X,Y\)以及两条直线\(L1,L2\),要求在四 ...

  2. [2019HDU多校第三场][HDU 6603][A. Azshara's deep sea]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6603 题目大意:给出一个凸包,凸包内有若干个圆,要求画尽可能多的对角线使得他们两两不在凸包内相交且不与 ...

  3. 2019HDU多校第四场 K-th Closest Distance ——主席树&&二分

    题意 给定 $n$ 个数,接下来有 $q$ 次询问,每个询问的 $l, r, p, k$ 要异或上一次的答案,才是真正的值(也就是强制在线).每次询问,输出 $[l, r]$ 内第 $k$ 小的 $| ...

  4. 2019HDU多校第四场 Just an Old Puzzle ——八数码有解条件

    理论基础 轮换与对换 概念:把 $S$ 中的元素 $i_1$ 变成 $i_2$,$i_2$ 变成 $i_3$ ... $i_k$ 又变成 $i_1$,并使 $S$ 中的其余元素保持不变的置换称为循环, ...

  5. 2019HDU多校第四场题解

    1001.AND Minimum Spanning Tree 传送门:HDU6614 题意:给你一个又n个点的完全图,点编号从1~n,每条边的权值为被连接的两点编号按位与后的值.现在要你找到最小生成树 ...

  6. 2018 HDU多校第四场赛后补题

    2018 HDU多校第四场赛后补题 自己学校出的毒瘤场..吃枣药丸 hdu中的题号是6332 - 6343. K. Expression in Memories 题意: 判断一个简化版的算术表达式是否 ...

  7. 牛客多校第四场sequence C (线段树+单调栈)

    牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...

  8. HDU 5768Lucky7(多校第四场)容斥+中国剩余定理(扩展欧几里德求逆元的)+快速乘法

    地址:http://acm.hdu.edu.cn/showproblem.php?pid=5768 Lucky7 Time Limit: 2000/1000 MS (Java/Others)    M ...

  9. Harvest of Apples (HDU多校第四场 B) (HDU 6333 ) 莫队 + 组合数 + 逆元

    题意大致是有n个苹果,问你最多拿走m个苹果有多少种拿法.题目非常简单,就是求C(n,0)+...+C(n,m)的组合数的和,但是询问足足有1e5个,然后n,m都是1e5的范围,直接暴力的话肯定时间炸到 ...

随机推荐

  1. K8S踩坑篇-master节点作为node节点加入集群

    前面我们二进制部署K8S集群时,三台master节点仅仅作为集群管理节点,所以master节点上中并未部署docker.kubelet.kube-proxy等服务.后来我在部署mertics-serv ...

  2. java源码 -- AbstractMap

    AbstractMap抽象类实现了一些简单且通用的方法,本身并不难.但在这个抽象类中有两个方法非常值得关注,keySet和values方法源码的实现可以值的学习. 抽象类通常作为一种骨架实现,为各自子 ...

  3. JAVA支持字符编码读取文件

    文件操作,在java中很常用,对于存在特定编码的文件,则需要根据字符编码进行读取,要不容易出现乱码 /** * 读取文件 * @param filePath 文件路径 */ public static ...

  4. python学习-16 列表list

    list 1.由[ ]括住,中括号内各元素由逗号隔开,各元素可以是数字,字符串,列表,布尔值等等. 例如: li = [521,"love",["john",& ...

  5. 利用Python进行数据分析_Numpy_基础_2

      Numpy数据类型包括: int8.uint8.int16.uint16.int32.uint32.int64.uint64.float16.float32.float64.float128.co ...

  6. Django 关联查询

    查询id=1的XXXXX关联的YYYYY信息 a = XXXXX.objects.get(id=1) a.YYYYY.all() 查询id=1的YYYYY关联的XXXXX信息 b = YYYYY.ob ...

  7. PAT(B) 1012 数字分类(Java)

    题目链接:1012 数字分类 代码 /** * Score 20 * Run Time 142ms * @author wowpH * @version 1.1 */ import java.util ...

  8. Composer安装yii2-imagine 压缩,剪切,旋转,水印

    安装:composer require --prefer-dist yiisoft/yii2-imagine 查看是否安装成功, 安装了两个目录分别是 vendor/imagine vendor/yi ...

  9. python实现数字0开始的索引,对应Execl的字母方法

    字母转数字方法: import re col = row = [] # 输入正确格式的定位,A2,AA2有效,AAB2无效 while len(col) == 0 or len(row) == 0 o ...

  10. 16-MySQL DBA笔记-调优基础理论和工具

    第五部分 性能调优与架构篇 本篇将为读者介绍性能调优的一些背景知识和理论,然后介绍一些工具的运用,最后介绍从应用程序到操作系统.到数据库.到存储各个环节的优化. 性能调优是一个高度专业的领域,它需要一 ...