【BZOJ 1067】 [SCOI2007]最大土地面积 旋转卡壳

本文介绍了一种利用凸包上单调性的旋转卡壳算法,并详细展示了其C++实现过程。该算法通过不断旋转来寻找最优解,适用于解决特定类型的几何问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

旋转卡(qiǎ)壳(ké)(我还特意去百度一波,但好像意思并不一样,中国文化博大精深啊)。

其实说简单点就是利用了在凸包上的单调性然后一直旋转,还是很好实现的。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define maxn 2021
using namespace std;
int top,n;
struct P{
	double x,y;
	P(double a=0,double b=0):x(a),y(b){}
	bool operator < (const P& b)const{return x==b.x?y<b.y:x<b.x;}
}p[maxn],s[maxn];
typedef P vec;
vec operator + (vec a,vec b){return vec(a.x+b.x,a.y+b.y);}
vec operator -(P a,P b){return vec(a.x-b.x,a.y-b.y);}
vec operator *(vec a,double p){return vec(a.x*p,a.y*p);}
vec operator /(vec a,double p){return vec(a.x/p,a.y/p);}
double cross(vec a,vec b){return a.x*b.y-a.y*b.x;}
double area2(P a,P b,P c){return fabs(cross(b-a,b-c));}
void make(){
	sort(p+1,p+1+n);s[top=1]=p[1];
	for(int i=2;i<=n;i++){
		while(top>1&&cross(s[top]-s[top-1],p[i]-s[top])<=0)top--;
		s[++top]=p[i];
	}int m=top;
	for(int i=n-1;i>=1;i--){
		while(top>m&&cross(s[top]-s[top-1],p[i]-s[top])<=0)top--;
		s[++top]=p[i];
	}top--;
}
void solve(){
	double ans=0;
	for(int x=1;x<=top;x++){
		int a=x%top+1,b=(x+1)%top+1;
		for(int y=x+2;y<=top;y++){
			while(a%top+1!=y&&cross(s[a+1]-s[x],s[y]-s[x])>cross(s[a]-s[x],s[y]-s[x]))a=a%top+1;
			while(b%top+1!=x&&cross(s[y]-s[x],s[b+1]-s[x])>cross(s[y]-s[x],s[b]-s[x]))b=b%top+1;
			ans=max(ans,area2(s[a],s[x],s[y])+area2(s[b],s[x],s[y]));
		}
	}
	printf("%.3lf",ans/2);
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
	make();solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值