BZOJ 1185: [HNOI2007]最小矩形覆盖 [旋转卡壳]
1185: [HNOI2007]最小矩形覆盖
Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 1435 Solved: 653
[Submit][Status][Discuss]
Description
Source
竟然1A了........哈哈哈哈哈哈哈哈哈哈
首先猜有一条边是凸边上的边(理由:不是的话我不会做)
然后旋转卡壳,最上面就是距离最远的点,最右面是点积最大,最左面是点积最小
然后就是各种向量运算 我用了v和u分别是宽和高方向的单位向量,感觉挺方便的....
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> using namespace std; typedef long long ll; const int N=5e4+5,INF=1e9; const double eps=1e-8; inline int sgn(double x){ if(abs(x)<eps) return 0; else return x<0?-1:1; } struct Vector{ double x,y; Vector(double a=0,double b=0):x(a),y(b){} bool operator <(const Vector &a)const{ return sgn(y-a.y)<0||(sgn(y-a.y)==0&&sgn(x-a.x)<0); } }; typedef Vector Point; Vector operator +(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);} Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);} Vector operator *(Vector a,double b){return Vector(a.x*b,a.y*b);} Vector operator /(Vector a,double b){return Vector(a.x/b,a.y/b);} bool operator ==(Vector a,Vector b){return sgn(a.x-b.x)==0&&sgn(a.y-b.y)==0;} double Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;} double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;} double Len(Vector a){return sqrt(Dot(a,a));} double Len2(Vector a){return Dot(a,a);} double DisTL(Point p,Point a,Point b){ Vector v1=p-a,v2=b-a; return abs(Cross(v1,v2)/Len(v2)); } int ConvexHull(Point p[],int n,Point ch[]){ sort(p+1,p+1+n); int m=0; for(int i=1;i<=n;i++){ while(m>1&&sgn(Cross(ch[m]-ch[m-1],p[i]-ch[m-1]))<=0) m--; ch[++m]=p[i]; } int k=m; for(int i=n-1;i>=1;i--){ while(m>k&&sgn(Cross(ch[m]-ch[m-1],p[i]-ch[m-1]))<=0) m--; ch[++m]=p[i]; } if(n>1) m--; return m; } Point pos[5]; void RotatingCalipers(Point p[],int n){ double ans=INF; p[n+1]=p[1]; int j=1,k=1,l=1; for(int i=1;i<=n;i++){ while(sgn(DisTL(p[j],p[i],p[i+1])-DisTL(p[j+1],p[i],p[i+1]))<=0) j=j%n+1; while(sgn(Dot(p[k]-p[i],p[i+1]-p[i])-Dot(p[k+1]-p[i],p[i+1]-p[i]))<=0) k=k%n+1; if(i==1) l=j; while(sgn(Dot(p[l]-p[i],p[i+1]-p[i])-Dot(p[l+1]-p[i],p[i+1]-p[i]))>=0) l=l%n+1; double len=Len(p[i+1]-p[i]); double h=DisTL(p[j],p[i],p[i+1]), w=Dot(p[k]-p[i],p[i+1]-p[i])/len+abs(Dot(p[l]-p[i],p[i+1]-p[i])/len); if(h*w<ans){ Vector v=(p[i+1]-p[i])/len; Vector u(-v.y,v.x); ans=h*w; pos[1]=v*Dot(p[l]-p[i],v)+p[i]; pos[2]=v*Dot(p[k]-p[i],v)+p[i]; pos[3]=pos[2]+u*h; pos[4]=pos[1]+u*h; } } int mn=1; for(int i=2;i<=4;i++) if(pos[i]<pos[mn]) mn=i; printf("%lf\n",ans); for(int i=mn;i<=4;i++) printf("%lf %lf\n",pos[i].x,pos[i].y); for(int i=1;i<mn;i++) printf("%lf %lf\n",pos[i].x,pos[i].y); } int n; Point p[N],ch[N]; int main(int argc, const char * argv[]) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); n=ConvexHull(p,n,ch); RotatingCalipers(ch,n); }
Copyright:http://www.cnblogs.com/candy99/