计算几何基础
凸包算法
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\n",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\n",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\n",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\n",fabs(t[(i+fir)%4].x),fabs(t[(i+fir)%4].y));
return 0;
}

浙公网安备 33010602011771号