题目链接: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. LeetCode 15. 三数之和(3Sum)

    15. 三数之和 15. 3Sum 题目描述 Given an array nums of n integers, are there elements a, b, c in nums such th ...

  2. 通过js操作,将div设置为contenteditable的内容设为全选状态

    因为div设置为contenteitable可编辑的文本内容用 select()选择全部内容不生效,所以只能用下列方法: 先 creatTextRange或者 createRange <div ...

  3. 关于npm install 报错 EAI_AGAIN reason: getaddrinfo EAI_AGAIN registry.npmjs.org

    在公司里使用了isa连接外网,刚开始使用npm 安装依赖的时候一直报错EAI_AGAIN reason: getaddrinfo EAI_AGAIN registry.npmjs.org,我们的老大给 ...

  4. (十四)JDBC入门

    目录 什么是JDBC 操作JDBC的步骤 DriverManager对象 数据库URL Connection对象 Statement对象 ResultSet对象 常用数据类型转换表 释放资源 SQL注 ...

  5. python学习-34 内置函数的补充

    其他内置函数 1.ord()    与chr()相反 2.pow() print(pow(3,3)) # 相当于3**3 print(pow(3,3,2)) # 相当于3*3%2 运行结果: 27 1 ...

  6. Firefox在新标签页打开“书签”和“搜索栏”(无需插件)

    转自   初来灬炸到的博客 前言 每次打开书签前,都需要创建新标签页. 每次搜索前,都需要创建新标签页.  这个真滴很麻烦.下面介绍的方法非常简单,不需要任何插件,通过修改浏览器参数即可. 名词 设置 ...

  7. Django入门(上)

    一.Web应用程序 1.web应用程序介绍 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件. 应用程序有两种模式 ...

  8. kettle工具的介绍和使用

    kettle详解(数据抽取.转换.装载) 原文地址链接:https://blog.csdn.net/qq_35731570/article/details/71123413   一:下载路径 当你要学 ...

  9. Luogu5327 ZJOI2019语言(树上差分+线段树合并)

    暴力树剖做法显然,即使做到两个log也不那么优美. 考虑避免树剖做到一个log.那么容易想到树上差分,也即要对每个点统计所有经过他的路径产生的总贡献(显然就是所有这些路径端点所构成的斯坦纳树大小),并 ...

  10. 模型汇总24 - 深度学习中Attention Mechanism详细介绍:原理、分类及应用

    模型汇总24 - 深度学习中Attention Mechanism详细介绍:原理.分类及应用 lqfarmer 深度学习研究员.欢迎扫描头像二维码,获取更多精彩内容. 946 人赞同了该文章 Atte ...