bzoj1069最大土地面积(旋转卡壳)

bzoj1069

给你n个点围成的土地 让你选择四个点 使构成的土地面积最大

注:

求对踵点的时候记录每对对踵点的len及dzd[]数组以便计算面积

从第一对对踵点开始 C D 分别是当前对踵点(最大土地面积的对角线)对应的另外两个点 显然寻找C D的过程同样符合旋转卡壳的单调性 所以可以O(n)维护出最大面积

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>

using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int MaxN = 4e3 + 5;

int n,Top;
double len[MaxN];
int dzd[MaxN];

struct Point{
	double x,y;
	Point(double x = 0,double y = 0):x(x),y(y){}
}p[MaxN],stack[MaxN],C;
typedef Point Vector;

int dcmp(double x){
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}

Vector operator + (Vector A,Vector B){ return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){ return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){ return Vector(A.x*p,A.y*p);}
bool operator == (const Point &a,const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}

double Dot(Vector A,Vector B){ return A.x*B.x+A.y*B.y;}
double Cross(Vector A,Vector B){ return A.x*B.y-A.y*B.x;}

double dis(Point A,Point B){
	return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
}

double compare(Point a,Point b,Point c){
	return Cross(c - a,c - b);
}

bool cmp(Point a,Point b){
	if(dcmp(compare(a,b,C)) == 0) return dis(a,C) < dis(b,C);
	return dcmp(compare(a,b,C)) > 0;
}

void Graham_scan(Point p[]){
	int i , k = 0;
	Top = 2;
	for(i = 1;i < n; i++){
		if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
	}
	swap(p[0],p[k]);
	C = p[0];
	sort(p + 1,p + n,cmp);
	stack[0] = p[0];
	stack[1] = p[1];
	stack[2] = p[2];
	for(int i = 3;i < n; i++){
		while(Top > 1 && compare(p[i],stack[Top],stack[Top - 1]) >= 0) Top--;
		stack[++Top] = p[i];
	}
	//[0,Top]
}

double RotatingCalipers(Point a[],int m){
	if(m == 1 || m == 2) return 0.0;
	a[m] = a[0];
	for(int i = 0;i <= m; i++) len[i] = 0;
	double res = 0.0;
	int j = 2;//0~1这条线开始 从点2开始找对踵点
	for(int i = 0;i < m; i++){//i∈[0,Top]
		while(Cross(a[i+1] - a[i],a[j] - a[i]) < Cross(a[i+1] - a[i],a[j+1] - a[i])) j = (j + 1) % m;
		double cur1 = dis(a[i],a[j]);
		if(cur1 >= len[i]){
			dzd[i] = j;
			len[i] = cur1;
		}
		double cur2 = dis(a[i + 1],a[j]);
		if(cur2 >= len[i + 1]){
			dzd[i + 1] = j;
			len[i + 1] = cur2;
		}
	}

	//把每一对对踵点当成矩形的长(四边形对角线)
	int C = 1,D = dzd[1];
	for(int i = 0;i < m; i++){
		//果宝机甲归位
		if(Cross(a[C] - a[i],a[dzd[i]] - a[i]) < 0) C = i;
		if(Cross(a[dzd[i]] - a[i],a[D] - a[i]) < 0) D = dzd[i];
		while(Cross(a[C] - a[i],a[dzd[i]] - a[i]) < Cross(a[C + 1] - a[i],a[dzd[i]] - a[i]) && Cross(a[C + 1] - a[i],a[dzd[i]] - a[i]) > 0) C = (C + 1) % m;
		while(Cross(a[dzd[i]] - a[i],a[D] - a[i]) < Cross(a[dzd[i]] - a[i],a[D + 1] - a[i]) && Cross(a[dzd[i]] - a[i],a[D + 1] - a[i]) > 0) D = (D + 1) % m;
		double cur = Cross(a[C] - a[i],a[dzd[i]] - a[i]) + Cross(a[dzd[i]] - a[i],a[D] - a[i]);

		res = max(res,cur);
	}
	return res;
}

int main()
{
	while(~scanf("%d",&n) && n){
		for(int i = 0; i < n; i++){
			scanf("%lf %lf",&p[i].x,&p[i].y);
		}
		if(n == 2 || n == 1){
			printf("0.00\n");
			continue;
		}
		Graham_scan(p);
		double ans = RotatingCalipers(stack,Top + 1);//Top + 1个点
		printf("%.3f\n",ans / 2.0);
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值