[2019HDU多校第四场][HDU 6617][D. Enveloping Convex]
题目链接: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]的更多相关文章
- [2019HDU多校第五场][HDU 6626][C. geometric problem]
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6626 题目大意:给出平面上六个点\(A,B,M,N,X,Y\)以及两条直线\(L1,L2\),要求在四 ...
 - [2019HDU多校第三场][HDU 6603][A. Azshara's deep sea]
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6603 题目大意:给出一个凸包,凸包内有若干个圆,要求画尽可能多的对角线使得他们两两不在凸包内相交且不与 ...
 - 2019HDU多校第四场 K-th Closest Distance ——主席树&&二分
		
题意 给定 $n$ 个数,接下来有 $q$ 次询问,每个询问的 $l, r, p, k$ 要异或上一次的答案,才是真正的值(也就是强制在线).每次询问,输出 $[l, r]$ 内第 $k$ 小的 $| ...
 - 2019HDU多校第四场 Just an Old Puzzle ——八数码有解条件
		
理论基础 轮换与对换 概念:把 $S$ 中的元素 $i_1$ 变成 $i_2$,$i_2$ 变成 $i_3$ ... $i_k$ 又变成 $i_1$,并使 $S$ 中的其余元素保持不变的置换称为循环, ...
 - 2019HDU多校第四场题解
		
1001.AND Minimum Spanning Tree 传送门:HDU6614 题意:给你一个又n个点的完全图,点编号从1~n,每条边的权值为被连接的两点编号按位与后的值.现在要你找到最小生成树 ...
 - 2018 HDU多校第四场赛后补题
		
2018 HDU多校第四场赛后补题 自己学校出的毒瘤场..吃枣药丸 hdu中的题号是6332 - 6343. K. Expression in Memories 题意: 判断一个简化版的算术表达式是否 ...
 - 牛客多校第四场sequence C (线段树+单调栈)
		
牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...
 - HDU 5768Lucky7(多校第四场)容斥+中国剩余定理(扩展欧几里德求逆元的)+快速乘法
		
地址:http://acm.hdu.edu.cn/showproblem.php?pid=5768 Lucky7 Time Limit: 2000/1000 MS (Java/Others) M ...
 - Harvest of Apples (HDU多校第四场 B) (HDU 6333 ) 莫队 + 组合数 + 逆元
		
题意大致是有n个苹果,问你最多拿走m个苹果有多少种拿法.题目非常简单,就是求C(n,0)+...+C(n,m)的组合数的和,但是询问足足有1e5个,然后n,m都是1e5的范围,直接暴力的话肯定时间炸到 ...
 
随机推荐
- Ctrl+Tab
			
很好用的快捷键. 可以在浏览器中自由切换,也可以在编辑器中自由切换.
 - [转帖]Linux系统下x86和ARM的区别有哪些?
			
Linux系统下x86和ARM的区别有哪些? https://www.cnblogs.com/alantu2018/p/9209143.html 其实界限 越来越小了.. 问题: 最近在用三星的一款i ...
 - SQL数据库基础语法
			
SQL语句的概述 SQL语言的分类 数据定义语言(Data Definition Language)主要用于修改.创建和删除数据库对象,其中包括CREATE ALTER DROP语句. 数据查询语 ...
 - 分布排序(distribution sorts)算法大串讲
			
ref : https://dsqiu.iteye.com/blog/1707383 本文内容框架: §1 鸽巢排序(Pigeonhole) §2 桶排序(Bucket Sort) §3 基数 ...
 - 谷歌(Google)学术镜像,谷歌镜像
			
谷歌(Google)学术镜像,谷歌镜像 2019-09-03 15:32:26 Hinton-wu 阅读数 6743 文章标签: 谷歌google学术镜像 更多 分类专栏: 其他 版权声明:本文为 ...
 - 自动化测试之if __name__ == '__main__'未运行
			
自动化测试之if __name__ == '__main__'未运行 添加Count类 calculator.py: class Count: def __init__(self,a,b): self ...
 - SQL Server系统函数:字符串函数
			
原文:SQL Server系统函数:字符串函数 1.字符转化为ASCII,把ASCII转化为字符,注意返回的值是十进制数 select ASCII('A'),ASCII('B'),ASCII('a') ...
 - core项目打包时发现有的项目的xml文件不会被打包进去,怎么办?
			
我打包后发现打包后的文件夹内,不存在xml文件,所以swagger加载失败:然后经过测试发现Core项目打包的时候是默认不包含Xml文件的,VS里面也没有办法设置. 解决方法:手动修改项目文件,找到你 ...
 - 客户端相关知识学习(十二)之iOS H5交互Webview实现localStorage数据存储
			
前言 最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识 webView开启支持H5 LocalStorage存储 有些时候我们发现写的本地存储没有起作用,那是因为默认WebVie ...
 - java轻松玩转localdatetime
			
废话不多说,直接上代码 //时间戳转LocalDateTime public static LocalDateTime getLocalDateTime(long timestamp) { Insta ...