旋转卡壳(求凸包直径)学习笔记 | 题解 P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳
前言
旋转卡壳(Rotating Calipers)可以在凸包上维护许多有用的信息,最常见的就是凸包直径(平面最远点对)。
注意:本文不介绍所谓的 “人类智慧” 乱搞做法。
算法流程
首先我们需要求出点集的凸包(我个人喜欢 Andrew 算法)。

然后我们考虑选定凸包的一条边所在的直线,比如 \(AB\)。然后找到凸包的所有顶点中离它最远的点,在这个例子中是 \(D\)。然后凸包直径就 可能 是 \(AD\) 或 \(BD\)。

然后我们继续。逆时针选择下一条边 \(AE\),这时我们发现最远点变成了 \(C\),然后尝试用 \(AC,EC\) 更新答案。以此类推。这样我们就找到了凸包直径。
但是这样子时间复杂度是 \(O(n^2)\) 的,应该无法通过。
但是根据以前的经验,似乎最远点也是逆时针旋转的。换句话说,逆时针遍历的点到直线的距离单调。
这也可以用凸包的凸性来解释。我无法给出详细证明,但是大家不妨手动画几个图,就可以感性的理解了。
于是我们就可以用一个漂亮的双指针解决了。
P145 【模板】旋转卡壳 代码
注意本题需要输出凸包直径的平方。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n;
const double eps=1e-9;
int dcmp(double x){
return (fabs(x)<=eps)?0:(x<0?-1:1);
}
struct Point{
double x,y;
Point(double X=0,double Y=0){x=X,y=Y;}
};
struct Vector{
double x,y;
Vector(double X=0,double Y=0){x=X,y=Y;}
};
inline Vector operator-(Point x,Point y){// 点-点=向量
return Vector(x.x-y.x,x.y-y.y);
}
inline double cross(Vector x,Vector y){ // 向量叉积
return x.x*y.y-x.y*y.x;
}
inline double operator*(Vector x,Vector y){ // 向量叉积
return cross(x,y);
}
inline double len(Vector x){ // 向量模长
return sqrt(x.x*x.x+x.y*x.y);
}
int stk[50005];
bool used[50005];
vector<Point> ConvexHull(Point* poly, int n){ // Andrew算法求凸包
int top=0;
sort(poly+1,poly+n+1,[&](Point x,Point y){
return (x.x==y.x)?(x.y<y.y):(x.x<y.x);
});
stk[++top]=1;
for(int i=2;i<=n;i++){
while(top>1&&dcmp((poly[stk[top]]-poly[stk[top-1]])*(poly[i]-poly[stk[top]]))<=0){
used[stk[top--]]=0;
}
used[i]=1;
stk[++top]=i;
}
int tmp=top;
for(int i=n-1;i;i--){
if(used[i]) continue;
while(top>tmp&&dcmp((poly[stk[top]]-poly[stk[top-1]])*(poly[i]-poly[stk[top]]))<=0){
used[stk[top--]]=0;
}
used[i]=1;
stk[++top]=i;
}
vector<Point> a;
for(int i=1;i<=top;i++){
a.push_back(poly[stk[i]]);
}
return a;
}
struct Line{
Point x;Vector y;
Line(Point X,Vector Y){x=X,y=Y;}
Line(Point X,Point Y){x=X,y=Y-X;}
};
inline double DistanceToLine(Point P,Line x){// 点到直线的距离
Vector v1=x.y, v2=P-x.x;
return fabs(cross(v1,v2))/len(v1);
}
double RoatingCalipers(vector<Point> poly){// 旋转卡壳
if(poly.size()==3) return len(poly[1]-poly[0]);
int cur=0;
double ans=0;
for(int i=0;i<poly.size()-1;i++){
Line line(poly[i],poly[i+1]);
while(DistanceToLine(poly[cur], line) <= DistanceToLine(poly[(cur+1)%poly.size()], line)){
cur=(cur+1)%poly.size();
}
ans=max(ans, max(len(poly[i]-poly[cur]), len(poly[i+1]-poly[cur])));
}
return ans;
}
Point poly[50005];
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>poly[i].x>>poly[i].y;
double v=RoatingCalipers(ConvexHull(poly, n));
cout<<(int)(v*v);
return 0;
}
旋转卡壳(求凸包直径)学习笔记 | 题解 P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳的更多相关文章
- luogu P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳
LINK:旋转卡壳 如题 是一道模板题. 容易想到n^2暴力 当然也能随机化选点 (还真有人过了 考虑旋转卡壳 其实就是对于某个点来说找到其最远的点. 在找的过程中需要借助一下个点的帮助 利用当前点到 ...
- UVa 1453 - Squares 旋转卡壳求凸包直径
旋转卡壳求凸包直径. 参考:http://www.cppblog.com/staryjy/archive/2010/09/25/101412.html #include <cstdio> ...
- POJ 2187 Beauty Contest【旋转卡壳求凸包直径】
链接: http://poj.org/problem?id=2187 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=22013#probl ...
- poj 2187 Beauty Contest , 旋转卡壳求凸包的直径的平方
旋转卡壳求凸包的直径的平方 板子题 #include<cstdio> #include<vector> #include<cmath> #include<al ...
- Yii框架学习笔记(二)将html前端模板整合到框架中
选择Yii 2.0版本框架的7个理由 http://blog.chedushi.com/archives/8988 刚接触Yii谈一下对Yii框架的看法和感受 http://bbs.csdn.net/ ...
- bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包
[HNOI2007]最小矩形覆盖 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 2081 Solved: 920 ...
- 位运算求最值 学习笔记 (待补充QAQ)
没有什么前言?直接进入正题qwq 俩俩异或 求最值: 建trie树 O(n)枚举每个数找这个数的最值,每次反走就成,还可以剪枝一波(如果在某位已经小于ans显然可以直接return? void Ins ...
- Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离
\(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接 ...
- 【洛谷 P1452】 Beauty Contest (二维凸包,旋转卡壳)
题目链接 旋转卡壳模板题把. 有时间再补总结吧. #include <cstdio> #include <cmath> #include <algorithm> u ...
- DirectX11 学习笔记2 - 加入关键事件 实现视角转换 旋转
上的程序的的基础上.在基类D3DBase添加摄像头功能 //录影机 void D3DBase::setCamera() { //关键事件 //假定A,S,D,W,Q,E,Z,X,C键被按下.动摄像机 ...
随机推荐
- 齐博x1前台后台地址跳转的处理
系统有三个入口,分别是 admin.php index.php member.php 所以就不能简单的使用TP默认的 url() 函数 而插件跟频道模块又有所不同,下面先讲解最基本的频道模块当中如何使 ...
- Multi-Channel PCIe QDMA Subsystem
可交付资料: 详细的用户手册 Design File:Post-synthesis EDIF netlist or RTL Source Timing and layout constraints,T ...
- mybatis-获取参数值的方式
MyBatis获取参数值的两种方式(重点) MyBatis获取参数值的两种方式:${}和#{} ${}的本质就是字符串拼接,#{}的本质就是占位符赋值 ${}使用字符串拼接的方式拼接sql,若为字符串 ...
- Pytest学习
pytest简介 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高. 使用介绍 编写规则 测试函数以t ...
- vue3中的defineProps,watch,computed
在vue3的setup语法糖中,defineProps不需要引入了 <script setup> import { computed } from '@vue/reactivity'; i ...
- golang基础语法学习
1.函数作为一等公民 2.驼峰命名法/大小写决定是否在包外见 3.包名应该是小写的单个单词命名 4. 包名应为其源码的基础名称,如encoding/base64,包名应为base64而不是encodi ...
- 面试官不按套路,竟然问我Java线程池是怎么统计线程空闲时间?
背景介绍: 你刚从学校毕业后,到新公司实习,试用期又被毕业,然后你又不得不出来面试,好在面试的时候碰到个美女面试官! 面试官: 小伙子,我看你简历上写的项目中用到了线程池,你知道线程池是怎样实现复用线 ...
- 配置MSTP功能示例
组网需求 在一个复杂的网络中,网络规划者由于冗余备份的需要,一般都倾向于在设备之间部署多条物理链路,其中一条作主用链路,其他链路作备份.这样就难免会形成环形网络,若网络中存在环路,可能会引起广播风暴和 ...
- i春秋破译
点开题目就是一段密文 TW5650Y - 0TS UZ50S S0V LZW UZ50WKW 9505KL4G 1X WVMUSL510 S001M0UWV 910VSG S0 WFLW0K510 1 ...
- beanshell报错:Error invoking bsh method: eval解决办法(beanshell 不支持Java中的泛型)
起因:在beanshell中读取CSV文件中的内容,相同的代码在IDEA中可以执行通过,但是在beanshell中报错: ERROR o.a.j.u.BeanShellInterpreter: Err ...