BZOJ 1069 [SCOI2007] 最大土地面积

Description

  在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成
的多边形面积最大。

Input

  第1行一个正整数N,接下来N行,每行2个数x,y,表示该点的横坐标和纵坐标。

Output

  最大的多边形面积,答案精确到小数点后3位。

Sample Input

5
0 0
1 0
1 1
0 1
0.5 0.5

Sample Output

1.000

HINT

数据范围 n<=2000, |x|,|y|<=100000

Source

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

旋转卡壳~

好棒的算法啊!

n<=2000,所以枚举对角线,然后分别在两边求出最大面积三角形,更新答案即可,其中枚举对角线ij后,在两边分别取两个点,while循环寻找最大面积的顶点,因为这个顶点的面积具有单调性,所以在j循环中不用每次新设xy,这里用到了旋转卡壳,复杂度不高~

(给的样例真是水,我原来那份到处是错的代码都能过样例……)

有几个注意点:

1.都是double型;

2.叉积小心先后顺序;

3.xy是先取模后+1,否则会超出范围;

4.事实证明,数组开大一点是好习惯。


#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

int n,tot;

struct node{
	double x,y;
}a[2005],c[2005];

double dis(node u,node v)
{
	return (u.x-v.x)*(u.x-v.x)+(u.y-v.y)*(u.y-v.y);
}

node operator -(node u,node v)
{
	node p;
	p.x=u.x-v.x;p.y=u.y-v.y;
	return p;
}

double operator *(node u,node v)
{
	return u.x*v.y-u.y*v.x;
}

bool operator <(node u,node v)
{
	double k=(u-a[1])*(v-a[1]);
	if(k==0) return dis(u,a[1])<dis(v,a[1]);
	return k<0;
}

void chan()
{
	int min=1;
	for(int i=2;i<=n;i++)
	  if(a[min].y>a[i].y || (a[min].y==a[i].y && a[min].x>a[i].x)) min=i;
	swap(a[min],a[1]);
	sort(a+2,a+n+1);
	c[++tot]=a[1];c[++tot]=a[2];
	for(int i=3;i<=n;i++)
	{
		while(tot>1 && (a[i]-c[tot-1])*(c[tot]-c[tot-1])<=0) tot--;
		c[++tot]=a[i];
	}
}

double cal()
{
	double ans=0;c[tot+1]=c[1];
	for(int i=1;i<=tot-2;i++)
	{
		int x=i%tot+1,y=(i+2)%tot+1;
		for(int j=i+2;j<=tot;j++)
		{
			while(x%tot+1!=j && (c[j]-c[i])*(c[x+1]-c[i])>(c[j]-c[i])*(c[x]-c[i])) x=x%tot+1;
			while(y%tot+1!=i && (c[y+1]-c[i])*(c[j]-c[i])>(c[y]-c[i])*(c[j]-c[i])) y=y%tot+1;
			ans=max(ans,(c[j]-c[i])*(c[x]-c[i])+(c[y]-c[i])*(c[j]-c[i]));
		}
	}
	return ans;
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
	chan();
	printf("%.3lf\n",cal()/2);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值