凸包算法
http://poj.org/problem?id=3348
#include<cstdio> #include<algorithm> using namespace std; const int N=5e5+11; int n,m; struct point{ int x,y; point(){} point(int _x,int _y): x(_x),y(_y){} friend inline point operator -(const point A,const point B){ return point(A.x-B.x,A.y-B.y); } friend inline int operator *(const point A,const point B){ return A.x*B.y-A.y*B.x; } inline int norm(){ return x*x+y*y; } }p[N],q[N]; inline bool operator <(const point A,const point B){ int det=(A-p[1])*(B-p[1]); if(det!=0)return det>0; return (A-p[1]).norm()<(B-p[1]).norm(); } inline void Graham(){ int id=1; for(register int i=2;i<=n;++i) if(p[i].x<p[id].x||p[i].x==p[id].x&&p[i].y<p[id].y) swap(p[i],p[id]); sort(p+2,p+n+1); q[++m]=p[1]; for(register int i=2;i<=n;++i){ while(m>=2&&(p[i]-q[m-1])*(q[m]-q[m-1])>=0)--m; q[++m]=p[i]; } } inline int Area(){ int res=0; q[m+1]=q[1]; for(register int i=1;i<=m;++i) res+=q[i]*q[i+1]; return (res>>1); } int main(){ scanf("%d",&n); for(register int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y); Graham(); printf("%d ",Area()/50); return 0; }
旋转卡壳
http://poj.org/problem?id=2187
#include<cstdio> #include<algorithm> using namespace std; const int N=5e5+11; int n,m; inline int max(int a,int b){ return a>b?a:b; } struct point{ int x,y; point(){} point(int _x,int _y): x(_x),y(_y){} friend inline point operator -(const point A,const point B){ return point(A.x-B.x,A.y-B.y); } friend inline int operator *(const point A,const point B){ return A.x*B.y-A.y*B.x; } inline int norm()const{ return x*x+y*y; } }p[N],q[N]; inline bool operator <(const point A,const point B){ int det=(A-p[1])*(B-p[1]); if(det!=0)return det>0; return (A-p[1]).norm()<(B-p[1]).norm(); } inline void Graham(){ int id=1; for(register int i=2;i<=n;++i) if(p[i].x<p[id].x||p[i].x==p[id].x&&p[i].y<p[id].y) swap(p[i],p[id]); sort(p+2,p+n+1); q[++m]=p[1]; for(register int i=2;i<=n;++i){ while(m>=2&&(p[i]-q[m-1])*(q[m]-q[m-1])>=0)--m; q[++m]=p[i]; } } inline int nxt(int x){ return x%m+1; } inline int area(const point A,const point B,const point C){ return (B-A)*(C-A); } inline int query(){ if(m==2)return (q[2]-q[1]).norm(); int res=0; for(register int i=1,j=3;i<=m;++i){ while(nxt(j)!=i&&area(q[i],q[i+1],q[j])<=area(q[i],q[i+1],q[nxt(j)]))j=nxt(j); res=max(res,(q[i+1]-q[j]).norm()); res=max(res,(q[i]-q[j]).norm()); } return res; } int main(){ scanf("%d",&n); for(register int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y); Graham(); printf("%d ",query()); return 0; }
BZOJ1069
http://www.lydsy.com/JudgeOnline/problem.php?id=1069
先做凸包,再枚举凸包的对角线,对于剩下的两个凸多边形做旋转卡壳
#include<cstdio> #include<algorithm> using namespace std; typedef double db; int n,m; const int N=1e6+11; struct point{ db x,y; point(){} point(db _x,db _y): x(_x),y(_y){} friend inline point operator-(const point A,const point B){ return point(A.x-B.x,A.y-B.y); } friend inline db operator*(const point A,const point B){ return A.x*B.y-A.y*B.x; } inline db norm()const{ return x*x+y*y; } }p[N],q[N]; inline bool operator<(const point A,const point B){ db det=(A-p[1])*(B-p[1]); if(det!=0)return det>0; return (A-p[1]).norm()<(B-p[1]).norm(); } inline void Graham(){ for(register int i=2;i<=n;++i) if(p[i].x<p[1].x||(p[i].x==p[1].x&&p[i].y<p[1].y)) swap(p[i],p[1]); sort(p+2,p+n+1); q[++m]=p[1];q[++m]=p[2]; for(register int i=3;i<=n;++i){ while(m>1&&(p[i]-q[m-1])*(q[m]-q[m-1])>=0)--m; q[++m]=p[i]; } } inline int nxt(int x){ return x%m+1; } inline db abs(db x){ return x>=0?x:-x; } inline db max(db a,db b){ return a>=b?a:b; } inline db solve(){ db ans=0; q[m+1]=q[1]; for(register int i=1,k,l;i<=m;++i){ l=nxt(nxt(k=nxt(i))); for(register int j=nxt(k);j<=m;++j){ while(nxt(k)!=j&&abs((q[k]-q[i])*(q[j]-q[i]))<=abs((q[nxt(k)]-q[i])*(q[j]-q[i])))k=nxt(k); while(nxt(l)!=i&&abs((q[l]-q[i])*(q[j]-q[i]))<=abs((q[nxt(l)]-q[i])*(q[j]-q[i])))l=nxt(l); ans=max(ans,1.00*(abs((q[k]-q[i])*(q[j]-q[i]))+abs((q[l]-q[i])*(q[j]-q[i])))); } } return ans*1.00/2.00; } int main(){ scanf("%d",&n); for(register int i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y); Graham(); printf("%.3lf",solve()); return 0; }
BZOJ1185
http://www.lydsy.com/JudgeOnline/problem.php?id=1185
先做凸包,再枚举凸包的一条边,用旋转卡壳做出该边的平行线,然后用点积求矩形宽的极值(具有单调性)
复杂度O(n^2)
#include<cmath> #include<algorithm> #include<cstdio> #define eps 1e-8 #define inf 1000000000 using namespace std; double ans=1e60; int n,top; struct P{ double x,y; P(){} P(double _x,double _y):x(_x),y(_y){} friend inline bool operator<(P a,P b){ return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y; } friend inline bool operator==(P a,P b){ return fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps; } friend inline bool operator!=(P a,P b){ return !(a==b); } friend inline P operator+(P a,P b){ return P(a.x+b.x,a.y+b.y); } friend inline P operator-(P a,P b){ return P(a.x-b.x,a.y-b.y); } friend inline double operator*(P a,P b){ return a.x*b.y-a.y*b.x; } friend inline P operator*(P a,double b){ return P(a.x*b,a.y*b); } friend inline double operator/(P a,P b){ return a.x*b.x+a.y*b.y; } friend inline double dis(P a){ return sqrt(a.x*a.x+a.y*a.y); } }p[50005],q[50005],t[5]; inline bool cmp(P a,P b){ double t=(a-p[1])*(b-p[1]); if(fabs(t)<eps)return dis(p[1]-a)-dis(p[1]-b)<0; return t>0; } inline void graham(){ for(register int i=2;i<=n;++i) if(p[i]<p[1]) swap(p[i],p[1]); sort(p+2,p+n+1,cmp); q[++top]=p[1]; for(register int i=2;i<=n;++i){ while(top>1&&(q[top]-q[top-1])*(p[i]-q[top])<eps)top--; q[++top]=p[i]; } q[0]=q[top]; } inline void RC(){ int l=1,r=1,p=1; double L,R,D,H; for(register int i=0;i<top;++i){ D=dis(q[i]-q[i+1]); while((q[i+1]-q[i])*(q[p+1]-q[i])-(q[i+1]-q[i])*(q[p]-q[i])>-eps)p=(p+1)%top; while((q[i+1]-q[i])/(q[r+1]-q[i])-(q[i+1]-q[i])/(q[r]-q[i])>-eps)r=(r+1)%top; if(i==0)l=r; while((q[i+1]-q[i])/(q[l+1]-q[i])-(q[i+1]-q[i])/(q[l]-q[i])<eps)l=(l+1)%top; L=(q[i+1]-q[i])/(q[l]-q[i])/D,R=(q[i+1]-q[i])/(q[r]-q[i])/D; H=(q[i+1]-q[i])*(q[p]-q[i])/D; if(H<0)H=-H; double tmp=(R-L)*H; if(tmp<ans){ ans=tmp; t[0]=q[i]+(q[i+1]-q[i])*(R/D); t[1]=t[0]+(q[r]-t[0])*(H/dis(t[0]-q[r])); t[2]=t[1]-(t[0]-q[i])*((R-L)/dis(q[i]-t[0])); t[3]=t[2]-(t[1]-t[0]); } } } int main(){ scanf("%d",&n); for(register int i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y); graham(); RC(); printf("%.5lf ",ans); int fir=0; for(register int i=1;i<=3;++i) if(t[i]<t[fir]) fir=i; for(register int i=0;i<=3;++i) printf("%.5lf %.5lf ",fabs(t[(i+fir)%4].x),fabs(t[(i+fir)%4].y)); return 0; }