http://poj.org/problem?id=2079 (题目链接)
题意
求凸包内最大三角形面积
Solution
旋转卡壳。
只会n²的做法,但是竟然过了。就是枚举每一个点,然后旋转卡壳另外两个点。先固定i,j这2个邻接的顶点。然后找出使三角形面积最大的那个k点。然后再固定i,枚举j点,由于k点是随着j点的变化在变化,所以k点不必从开头重新枚举。
之后去网上看了下O(n)的做法,当时就感觉有点鬼,打了一遍交上去Wa了,鬼使神差拍出一组数据好像可以把网上O(n)的做法全部卡掉,但是我也还搞不清为什么这样做是错的。
这3个数据都是同一个凸包,面积都是15.00。
O(n)代码
// poj2079
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#define esp 1e-8
#define inf 2147483640
#define LL long long
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline LL getint() {
LL x=0,f=1;char ch=getchar();
while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} const int maxn=50010;
struct point {int x,y;}p[maxn],p0; int cross(point p0,point p1,point p2) {
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
double dis(point a,point b) {
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(point a,point b) {
int t=cross(p0,a,b);
if (t>0) return 1;
if (t<0) return 0;
return dis(p0,a)<dis(p0,b);
}
int Graham(int n) {
if (n==1) return 1;
int k=1,top=2;
for (int i=1;i<=n;i++)
if (p[i].y==p[k].y ? p[i].x<p[k].x : p[i].y<p[k].y) k=i;
p0=p[k];p[k]=p[1];p[1]=p0;
sort(p+2,p+1+n,cmp);
for (int i=3;i<=n;i++) {
while (top>1 && cross(p[top-1],p[top],p[i])<=0) top--;
p[++top]=p[i];
}
return top;
}
double RC(int n) {
int ans=0;
p[n+1]=p[1];
int i=1,j=2,k=3,t;
while (k!=1) {
int ii=i,jj=j,kk=k;
while ((t=abs(cross(p[i],p[k],p[j])))<abs(cross(p[i],p[k+1],p[j]))) k=k%n+1;
ans=max(ans,t);
while ((t=abs(cross(p[i],p[k],p[j])))<abs(cross(p[i],p[k],p[j+1]))) j=j%n+1;
ans=max(ans,t);
while ((t=abs(cross(p[i],p[k],p[j])))<abs(cross(p[i+1],p[k],p[j]))) i=i%n+1;
ans=max(ans,t);
if (ii==i && jj==j && kk==k) k=k%n+1;
}
return (double)ans/2.0;
}
int main() {
int n;
while (scanf("%d",&n)!=EOF && n>0) {
for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
n=Graham(n);
printf("%.2f\n",RC(n));
}
return 0;
}
O(n²)代码
// poj2079
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#define esp 1e-8
#define inf 2147483640
#define LL long long
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline LL getint() {
LL x=0,f=1;char ch=getchar();
while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
} const int maxn=50010;
struct point {int x,y;}p[maxn],p0; int cross(point p0,point p1,point p2) {
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
double dis(point a,point b) {
return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(point a,point b) {
int t=cross(p0,a,b);
if (t>0) return 1;
if (t<0) return 0;
return dis(p0,a)<dis(p0,b);
}
int Graham(int n) {
if (n==1) return 1;
int k=1,top=2;
for (int i=1;i<=n;i++)
if (p[i].y==p[k].y ? p[i].x<p[k].x : p[i].y<p[k].y) k=i;
p0=p[k];p[k]=p[1];p[1]=p0;
sort(p+2,p+1+n,cmp);
for (int i=3;i<=n;i++) {
while (top>1 && cross(p[top-1],p[top],p[i])<=0) top--;
p[++top]=p[i];
}
return top;
}
double RC(int n) {
int ans=0;
p[n+1]=p[1];
for (int i=1;i<=n;i++) {
int j=i%n+1,k=(i+1)%n+1;
while (abs(cross(p[i],p[j],p[k]))<abs(cross(p[i],p[j],p[k+1]))) k=k%n+1;
while (i!=j && i!=k) {
ans=max(ans,abs(cross(p[i],p[j],p[k])));
while (abs(cross(p[i],p[j],p[k]))<abs(cross(p[i],p[j],p[k+1]))) k=k%n+1;
j=j%n+1;
}
}
return (double)ans/2.0;
}
int main() {
int n;
while (scanf("%d",&n)!=EOF && n>0) {
for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
n=Graham(n);
printf("%.2f\n",RC(n));
}
return 0;
}