题目链接: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. java学习基础知识入门

    基础入门知识(一) 一.java技术的分类 java按照技术标准和应用场景的不同分为三类,分别是JAVASE.JAVAEE.JAVAME JAVASE : 平台标准版,用于开发部署桌面,服务器以及嵌入 ...

  2. Windows10下安装numpy

    1.https://bootstrap.pypa.io/get-pip.py 下载get-pip.py(右键另存为即可) 2.命令行下在get-pip.py所在文件夹下运行get-pip.py 3.命 ...

  3. 利用Python进行数据分析_Pandas_层次化索引

    申明:本系列文章是自己在学习<利用Python进行数据分析>这本书的过程中,为了方便后期自己巩固知识而整理. 层次化索引主要解决低纬度形式处理高纬度数据的问题 import pandas ...

  4. 通过pip命令导出和导入Python环境安装包

    我们在开发完代码后,一般需要将依赖包导出,然后在移植到其他系统使去安装,保证环境正常   导出Python环境安装包[root@bogon ~]# pip freeze > packages.t ...

  5. 阿里云Centos7 搭建laravel

    最近在考虑学习laravel框架,唔 现在服务器搭建一下. laravel是依赖composer的,首先在linux服务器下先安装composer.运行composer需要 php 5.3以上版本, ...

  6. git命令 撤销文件修改

    git checkout . #本地所有修改的.没有的提交的,都返回到原来的状态 git checkout src/views/useChapter.vue #撤销项目目录 src/views/文件夹 ...

  7. Java Web 深入分析(3) CDN

    CDN (Content Delivery NetWork) 内容分发网络,它是构筑在现有互联网基础上的一种先进的流量分配网络.区别于镜像,相当于是 CDN = 镜像(mirror) + 缓存(Cac ...

  8. 微软升级 WSL Window Subsystem for Linux Win10系统自带Linux

    在设计之初,微软就允许类似于Win32这种子系统运行于windows NT内核之上,它可以为上层应用提供编程接口,同时避免应用去实现内核里的一些调用细节.NT内核的设计在最开始就可以支持POSIX,O ...

  9. java01_简介_开发环境

    JAVA的前世今生 美国SUN(Stanford University Network)公司,在中国大陆的正式中文名为"太阳计算机系统(中国)有限公司",在中国台湾的正式中文名为& ...

  10. taglist and nerdtree

    函数:function! s:Tlist_Window_Exit_Only_Window()中的winbunr(2)改为winbunr(3),即只剩2个窗口时关闭,考虑到2个窗口肯定是同时存在,所以这 ...