旋转卡壳 模板+笔记整理

先放一道例题:

【题目描述】:

约翰农夫的母牛贝西,刚刚在牛选美比赛赢得第一名,赢得了“世界牛小姐”称号。为了传播善意,贝西将参观世界各地的农场N(2 < = N < = 50000)。为简单起见,世界将被表示成一个二维平面,其中每个农场位于一对整数坐标(x,y),其值在-2000000~2000000范围内。没有两个农场共享相同的坐标。

尽管贝西旅行中走农场之间的直线,但一些农场之间的距离可能很大,所以她想带着一个手提箱,足够她装食物,即使最远的距离。她想确定旅行中最大可能的距离,这样她才能决定箱子的大小。帮助贝西计算所有成对的农场间最大距离。(最远点对)

【输入描述】:

第一行一个整数N

以下N行,每行两个整数,表示一个农场的坐标。

【输出描述】:

一行,一个整数表示最远一对农场距离的平方。

【样例输入】:

4
0 0
0 1
1 1
1 0

【样例输出】:

2

【时间限制、数据范围及描述】:

时间:1s 空间:256M

2 < = N < = 50000


我们可以将问题转化为标准的旋转卡壳解决的问题:将所有点做一遍凸包后求凸包的直径问题。






AC代码:

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<cmath>  
#define ll long long
using namespace std;  
const int Maxn=100005;  
struct node{  
    ll x,y;  
}a[Maxn],ans[Maxn];  
ll n,k,lim,ansn;  
node operator -(const node &a,const node &b){  
    node c;  
    c.x=a.x-b.x;c.y=a.y-b.y;  
    return c;  
}  
inline ll chaji(node a,node b){
    return a.x*b.y-a.y*b.x;  
}
inline ll mx(ll x,ll y){
	return x>y?x:y;
}
inline ll dianji(node a,node b){
	return a.x*b.x+a.y*b.y;
}
inline ll dis(node a,node b){  
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);  
}   
bool cmp(node x,node y){  
    if(x.y!=y.y)return x.y<y.y;  
    return x.x<y.x;
}  
bool check(node o,node x,node y){  
    return chaji((x-o),(y-o))>0?0:1;  
}  
void convex(){  
    k=0;
    sort(a+1,a+1+n,cmp);  
    for(ll i=1;i<=n;i++){  
        while(k>=2&&check(ans[k-1],ans[k],a[i]))k--;
        ans[++k]=a[i];  
    }  
    lim=k;  
    for(ll i=n;i>=1;i--){
        while(k>=lim+1&&check(ans[k-1],ans[k],a[i]))k--;
        ans[++k]=a[i];  
    }  
    if(n>1)k--; 
}  
inline ll step(ll x){
	x=x+1;
	if(x>n)x=1;
	return x;
}
void rotate(){
	ll now=2,ansn=0;
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lld%lld",&a[i].x,&a[i].y);
	}
	convex();
	ans[n+1]=ans[1];
	for(ll i=1;i<=k;i++){
		while(chaji((ans[i+1]-ans[i]),(ans[now+1]-ans[i]))>chaji((ans[i+1]-ans[i]),(ans[now]-ans[i]))){now=step(now);}
		ansn=mx(ansn,mx(dis(ans[i],ans[now]),dis(ans[i+1],ans[now+1])));
	}
	printf("%lld\n",ansn);
}
int main(){  
	rotate();
    return 0;  
}  


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值