所谓旋转卡壳,就是旋转起来的卡壳

(逃)

前言

前置知识:凸包
个人感觉很像 two-pointers 算法。
能够在优秀的线性时间复杂度内完成总多求最值(周长、面积…)的神奇操作。

解析

给出情境:

给出平面内的 nnn 个点,求出所有点中的最远点对。
n≤105n\le 10^5n≤105

首先有一个结论:最远点对一定都是点集的凸包的顶点
较为显然,证明可以考虑把凸包内的点延长到凸包一条边上,边两边的顶点一定有一个更优。

那么我们就转化成了求凸包上的最远点对,这个问题也叫做凸包的直径问题

给出一些定义:

凸包的切线:若一条直线过凸包上的一点或一边,且整个凸包都在直线的同侧或在线上,那么我们就称这条直线为凸包的切线。
对踵点:如果经过凸包的两个顶点,可以作两条平行的凸包的切线,那么就称这两个点是一对对踵点。

不难发现,最远点对一定是一对对踵点。
然而个人感觉旋转卡壳这个知识点完全不需要这个概念。

考虑换一个角度,每次枚举边,然后用到边距离最远的点和边的两端点的距离来更新答案。(每次更新答案的点其实都是对踵点)
显然最优答案一定会被枚举到。
不难发现,如果我们逆时针枚举边,最远点的位置也是在逆时针旋转。
那么我们利用类似 two-pointers 的思想就可以线性的求出答案。
问题得以解决。

实现的细节上,我比较喜欢的方法是一开始先扫一遍暴力找到指针的起始位置,而不是倍长(野蛮)或者每次移动指针都更新答案(玄学)。

代码

P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}//basic declare
//#define double long double
const double eps=1e-10;
const double pi=acos(-1.0);//---about vectors (or points)//definition
struct V{double x,y;V():x(0),y(0){}V(double a,double b):x(a),y(b){}
};
V ans[10];//declared for other functions
int tot;
inline void input(V &a){scanf("%lf%lf",&a.x,&a.y);}
void print(const V &a,int op=1){printf("%.10lf %.10lf",a.x,a.y);putchar(op?10:32);}
//op:endl or space//basic operation
inline V operator + (const V &a,const V &b){return (V){a.x+b.x,a.y+b.y};}
inline V operator - (const V &a,const V &b){return (V){a.x-b.x,a.y-b.y};}
inline V operator * (const double &x,const V &a){return (V){a.x*x,a.y*x};}
inline V operator * (const V &a,const double &x){return (V){a.x*x,a.y*x};}
inline V operator / (const V &a,const double x){return (V){a.x/x,a.y/x};}
inline bool operator == (const V &a,const V &b){return abs(a.x-b.x)<eps&&abs(a.y-b.y)<eps;}
inline bool operator != (const V &a,const V &b){return !(a==b);}
inline double operator * (const V &a,const V &b){return a.x*b.x+a.y*b.y;}
inline double operator ^ (const V &a,const V &b){return a.x*b.y-a.y*b.x;}
inline double len(const V &a){return sqrt(a.x*a.x+a.y*a.y);}
inline V mid(const V &a,const V &b){return (V){(a.x+b.x)/2,(a.y+b.y)/2};}
inline V chui(const V &a){return (V){a.y,-a.x};}//not take direction into account
inline V danwei(const V &a){return a/len(a);}
inline double tri_S(const V &a,const V &b,const V &c){return abs((b-a)^(c-a))/2;}//always be non-negative
inline bool operator < (const V &a,const V &b){return a.x<b.x-eps||(abs(a.x-b.x)<eps&&a.y<b.y-eps);
}
inline double ang(const V &a,const V &b){return acos((a*b)/len(a)/len(b));}
inline V rotate(const V &o,double t){//COUNTER_CLOCKWISEdouble s=sin(t),c=cos(t);return (V){o.x*c-o.y*s,o.x*s+o.y*c};
}const int N=1e5+100;
const int M=505;
int n,m;
V p[N],zhan[N];
bool cmp(V a,V b){double d=(a-p[1])^(b-p[1]);if(abs(d)>eps) return d>0;else return len(a-p[1])<len(b-p[1]);
}
void graham(V *p,int &n){int top=0;sort(p+1,p+1+n);sort(p+2,p+1+n,cmp);top=0;for(int i=1;i<=n;i++){while((top>1&&((zhan[top]-zhan[top-1])^(p[i]-zhan[top]))<=0)) --top;zhan[++top]=p[i];}memcpy(p,zhan,sizeof(zhan));n=top;return;
}
inline ll calc(const V &a,const V &b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+eps;
}
ll rotate_calipers(V *p,int n){ll res(0);int pl=1;for(int i=2;i<=n;i++){if(((p[2]-p[1])^(p[pl]-p[2]))<((p[2]-p[1])^(p[i]-p[2]))) pl=i;}for(int i=1;i<=n;i++){while(((p[i+1]-p[i])^(p[pl]-p[i+1]))<((p[i+1]-p[i])^(p[pl+1]-p[i+1]))){pl=(pl+1)%n;res=max(res,max(calc(p[i],p[pl]),calc(p[i+1],p[pl])));}res=max(res,max(calc(p[i],p[pl]),calc(p[i+1],p[pl])));}return res;
}
signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();for(int i=1;i<=n;i++) input(p[i]);graham(p,n);p[0]=p[n];p[n+1]=p[1];//for(int i=1;i<=n;i++) print(p[i]);//putchar('\n');printf("%lld\n",rotate_calipers(p,n));return 0;
}
/*
3 5
0 -2
-5 3
0 -7
*/

模板:旋转卡壳(计算几何)相关推荐

  1. [模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和

    一些基本的定义在这里: [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算 自适应Simpson Simpson's Rule: \[ \int ^b_a f(x)dx\approx ...

  2. 算法学习:计算几何旋转卡壳

    [定义] [对踵点]多边形上存在平行切线的两点 [多边形半径]多边形上任意两点的最大长度 [旋转卡壳] 选取y轴上,最高和最低的两个点,令两条平行于x轴的线切过这两点 然后我们开始让这两条线旋转 当一 ...

  3. 计算几何之 旋转卡壳 代码模板与证明

    旋转卡壳 旋转卡壳这个算法很形象,一般用来在O(nlogn)O(nlogn)O(nlogn)的时间复杂度下求最远点对问题,就是求平面中任意两点的最远距离. 一般求最远点对问题得枚举两个点,所以复杂度是 ...

  4. POj2187 【模板】旋转卡壳 / 选美大赛

    POj2187 [模板]旋转卡壳 / 选美大赛 题目描述 农夫约翰奖的牛贝西(Bessie)刚刚在牛选美比赛中获得第一名,并获得了"牛世界小姐"的头衔.结果,贝茜将参观世界各地的N ...

  5. Beauty Contest(凸包 + 旋转卡壳(模板))

    Beauty Contest 直接跑一个凸包,然后跑一跑旋转卡壳,求最大值就行了. /*Author : lifehappy */ #include <cstdio> #include & ...

  6. 计算几何之旋转卡壳算法

    一.目录 一些历史: 1978年, M.I. Shamos's Ph.D. 的论文"Computational Geometry"标志着计算机科学的这一领域的诞生. 当时他发表成果 ...

  7. [POJ2187]Beauty Contest(计算几何-旋转卡壳-最远点对)

    题目: 我是超链接 题解: 值得一提的是,这是一个"不定向"算法,为什么呢,因为ta的名字不定哈哈哈,旋转卡壳一共有2*3*2*2=24种不同的读音哦 旋转卡壳可以解决:凸多边形最 ...

  8. 旋转卡壳凸包(不用一下子就学完所有)

    目录 前言 参考博客 前置知识 1.极角排序 2.凸包(默认逆时针) 3.对踵点 旋转卡壳能解决的各类问题 1.计算距离 1.1凸多边形直径 1.2凸多边形宽 1.3凸多边形间最大距离 1.4凸多边形 ...

  9. Gym - 102460L Largest Quadrilateral(几何-凸包+旋转卡壳求最大的四边形面积)

    题目链接:点击查看 题目大意:在笛卡尔坐标系上给出 n 个点,要求选出四个点,使得组成的四边形面积最大,求出这个最大的面积,注意此处组成的四边形不是严格意义上的四边形,只需要选四个点就行 题目分析:首 ...

最新文章

  1. Opencv函数手册
  2. 什么是Closed-form solution?
  3. java判断波动的曲线是否大体平衡_基于标的物价格和波动率的期权投资策略
  4. SUSE11sp3 perf工具安装过程
  5. 十天精通CSS3(11)
  6. web前端入门学习 css(3)(背景相关)
  7. float、double(浮点数)区别还有和decimal(定点数)的比较
  8. VC中GetLastError()获取错误信息的使用,以及错误代码的含义
  9. 重磅!Python再次第一,Java和C下降,凭什么?
  10. 五一新闻回顾:XP SP3悄发布 微软雅虎终谈崩
  11. oracle 误删除数据,回退表数据
  12. 关于解决The Operation Couldn't be Completed
  13. MT8377 MT8389 MT6589 MT6577解析
  14. 深度学习笔记-吴恩达
  15. 360漏洞修复卡在正在安装的解决方法
  16. 阿里云迁移工具推荐最佳实践:KVM虚拟化迁移到阿里云
  17. 计算机结构体系-CISC与RISC
  18. Python环境下数据处理常用命令
  19. SolidWorks学习笔记5创建基准面,基准线,基准点
  20. (一)ArcGIS JS 发布动态地图服务

热门文章

  1. 小程序 订阅消息 wx.requestSubscribeMessage 允许 拒绝 情况的返回 结果
  2. EXCEL设置下拉选项,选项带颜色
  3. ​浅谈 Java 后端开发工程师腾讯面试经历分享总结
  4. 记一次排查服务器被挖矿记录
  5. 期货开户手续费是怎么查询?
  6. C. Alice and the Cake
  7. python123 第四次作业_第四次作业
  8. 2022-2028全球与中国多通道光纤旋转接头(FORJ)市场现状及未来发展趋势
  9. [可联网]ps4共享屏幕到笔记本
  10. 解决Linux“Device is busy”与磁盘只读