省选专练之HNOI2007最小矩形覆盖&模板:旋转卡壳

1:先求出凸包

2:由于矩形的一条边必然在凸包上枚举这条边

3:左右(l,r)利用点乘算出(因为存在cos)

4:上下(p)利用叉乘算出(因为存在sin)

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-12;
const int N=2e6+100;
int cmp(double A){
    if(fabs(A)<eps)return 0;
    return A>0?1:-1;
}
int equal(double A,double B){
    return (cmp(A-B)==0);
}
struct Point{
    double x,y;
    Point(double _x=0.0,double _y=0.0):x(_x),y(_y){}
    friend bool operator <= (Point A,Point B){return fabs(A.y-B.y)<eps?A.x<B.x:A.y<B.y;}
    friend bool operator < (Point A,Point B){return A.x<B.x||(A.x==B.x&&A.y<B.y);}
    friend Point operator + (Point A,Point B) {return Point(A.x+B.x,A.y+B.y);}
    friend Point operator - (Point A,Point B) {return Point(A.x-B.x,A.y-B.y);}
    friend Point operator * (Point A,double k){return Point(A.x*k,A.y*k)    ;}
    friend Point operator / (Point A,double k){return Point(A.x/k,A.y/k)    ;}
    friend bool operator == (Point A,Point B) {return A.x==B.x&&A.y==B.y;}
    friend double dis 		(Point A		 ){return sqrt(A.x*A.x+A.y*A.y) ;} 
}P[N],Q[N],A[5];
int top=0;
int n;
double Cross(Point A,Point B){
    return A.x*B.y-A.y*B.x;
}
double Dot(Point A,Point B){
    return A.x*B.x+A.y*B.y;
}
void Push(Point now){
    while(Cross((now-Q[top-1]),(Q[top]-Q[top-1]))>0||now==Q[top])top--;
    top++;
    Q[top]=now;
}
void Graham(){
    sort(P+1,P+1+n);
    Q[0]=Q[top=1]=P[1];
    for(int i=2;i<=n;i++){
//		if(P[i].x==3.6071)cout<<i<<'\n';
        Push(P[i]);
    }
    for(int i=n-1;i>=2;i--){
        Push(P[i]);
    }
    Q[0]=Q[top];
}
double ans=1e18;
void RC(){
    int l=1;
    int r=1;
    int p=1;
//	for(int i=0;i<top;i++){
//		cout<<Q[i].x<<" "<<Q[i].y<<'\n';
//	}
    for(int i=0;i<top;i++){
//		cout<<Q[i].x<<" "<<Q[i].y<<'\n';
//		cout<<i<<" "<<p<<'\n';
        while(cmp(Cross(Q[i+1]-Q[i],Q[p+1]-Q[i])  -Cross(Q[i+1]-Q[i],Q[p]-Q[i])>=0) ){
            p=(p+1)%top;
//			cout<<"Cut"<<" "<<p<<'\n';

        }		
        while(cmp(Dot  (Q[i+1]-Q[i],Q[r+1]-Q[i])  -Dot  (Q[i+1]-Q[i],Q[r]-Q[i]))>=0 )r=(r+1)%top;
        if(i==0)l=r;
        while(cmp(Dot  (Q[i+1]-Q[i],Q[l+1]-Q[i])-Dot  (Q[i+1]-Q[i],Q[l]-Q[i]))   <=0)l=(l+1)%top;
        double D=dis(Q[i+1]-Q[i]);
        double L=Dot  (Q[i+1]-Q[i],Q[l]-Q[i])/D;
        double R=Dot  (Q[i+1]-Q[i],Q[r]-Q[i])/D;
        double H=Cross(Q[i+1]-Q[i],Q[p]-Q[i])/D;
//		cout<<D<<" "<<H<<" "<<L<<" "<<R<<'\n';
//		cout<<"------"<<'\n';
        H=fabs(H);
        double tmp=fabs(R-L)*H;
//		ans=min(ans,fabs(R-L)*H);
        if(tmp<ans){
            ans=tmp;
            A[0]=Q[i]+(Q[i+1]-Q[i])*(R/D);
            A[1]=A[0]+(Q[r]-A[0])*(H/dis(A[0]-Q[r]));
            A[2]=A[1]-(A[0]-Q[i])*((R-L)/dis(Q[i]-A[0]));
            A[3]=A[2]-(A[1]-A[0]);
        }
    }
}
struct Node{
    double x,y;
}B[5];
bool comp(const Node &A, const Node &B) {
    return (A.y<B.y)||(A.y==B.y&&A.x<B.x);
}
int main(){
// 	freopen("1986.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&P[i].x,&P[i].y);
    }
    Graham();
//	cout<<"Graham"<<'\n';
    RC();
    printf("%.5lf\n",ans);
    int fir=0;
    for(int i=1;i<=3;i++)
        if(A[i]<=A[fir])
            fir=i;
    for(int i=0;i<=3;i++)
        printf("%.5lf %.5lf\n",fabs(A[(i+fir)%4].x)>1e-12?A[(i+fir)%4].x:0.00000,fabs(A[(i+fir)%4].y)>1e-12?A[(i+fir)%4].y:0.00000);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/81072199