您的位置:首页 > 其它

【BZOJ】【1069】【SCOI2007】最大土地面积

2015-05-13 17:31 260 查看

计算几何/旋转卡壳

  从已知点中选出四个使得选出的四边形面积最大,很明显我们应该在凸包上搞。

  我一开始的思路是:枚举 i ,找到 i 的对锺点cur1,这两个点将凸包分成了两半,我们在左半中枚举一个 j ,然后在右半中找一个离 j 最远的“对锺点”(可能不是?反正找的是最远……)cur2,然后求cur1和cur2都是单调的,复杂度为枚举 i, j的$O(n^2)$

  然而跪了= =然后我去Orz了proverbs的题解,得到启示:我们可以枚举一条对角线,然后在左半和右半中各找一条跟这条对角线最远的点!这两个点的寻找明显是单调的,复杂度为枚举对角线的两个端点的$O(n^2)$

  Orzzzzz思路还是不够开阔啊

  一开始错我还以为是旋转卡壳写错了……后来发现原来是凸包写错了QAQ

/**************************************************************
Problem: 1069
User: Tunix
Language: C++
Result: Accepted
Time:284 ms
Memory:1340 kb
****************************************************************/

//BZOJ 1069
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
typedef long long LL;
inline int getint(){
int r=1,v=0; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
return r*v;
}
const int N=2010;
/*******************template********************/
struct Poi{
double x,y;
Poi(){}
Poi(double x,double y):x(x),y(y){}
void read(){scanf("%lf%lf",&x,&y);}
}p
,ch
;
typedef Poi Vec;
Vec operator - (const Poi &a,const Poi &b){return Vec(a.x-b.x,a.y-b.y);}
bool operator < (const Poi &a,const Poi &b){return a.x<b.x || (a.x==b.x && a.y<b.y);}
inline double Dot(const Poi &a,const Poi &b){return a.x*b.x+a.y*b.y;}
inline double Cross(const Poi &a,const Poi &b){return a.x*b.y-a.y*b.x;}

int n,m;
double ans;
void graham(Poi *p,int n){
sort(p+1,p+n+1);
ch[++m]=p[1];
F(i,2,n){
while(m>1 && Cross(ch[m]-ch[m-1],p[i]-ch[m-1])<=0) m--;
ch[++m]=p[i];
}
int k=m;
D(i,n-1,1){
while(m>k && Cross(ch[m]-ch[m-1],p[i]-ch[m-1])<=0) m--;
ch[++m]=p[i];
}
if (n>1) m--;
}
double getans(Poi a1,Poi a2,Poi b1,Poi b2){
return Cross(a2-a1,b1-a1)+Cross(b2-b1,a1-b1);
}
void rot(Poi *p,int n){
int cur1=2,cur2,j;
F(i,1,n) p[i+n]=p[i];
F(i,1,n-1){
cur1=i+1;
j=cur1+1;
cur2=j+1;
for(;j<i+n-1;j++){
while(Cross(p[cur1+1]-p[i],p[j]-p[i]) > Cross(p[cur1]-p[i],p[j]-p[i]))
cur1=cur1%n+1;
while(Cross(p[cur2+1]-p[j],p[i]-p[j]) > Cross(p[cur2]-p[j],p[i]-p[j])){
cur2=cur2%n+1;
if (cur2>=i+n-1) break;
}
if (cur2>i+n-1) break;
ans=max(ans,getans(p[i],p[cur1],p[j],p[cur2]));
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1069.in","r",stdin);
//  freopen("1069.out","w",stdout);
#endif
n=getint();
F(i,1,n) p[i].read();
graham(p,n);
rot(ch,m);
printf("%.3f\n",ans*0.5);
return 0;
}


View Code

1069: [SCOI2007]最大土地面积

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 1853 Solved: 683
[Submit][Status][Discuss]

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

[Submit][Status][Discuss]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: