zoukankan      html  css  js  c++  java
  • BZOJ 1185: [HNOI2007]最小矩形覆盖(旋转卡壳)

    传送门

    解题思路

      首先有一个结论是最小覆盖矩形的一条边一定是凸包上的一条边,那么就可以枚举凸包上的点,然后旋转卡壳卡出其余三个点。算坐标的时候拿向量去乘一下。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    
    using namespace std;
    const int MAXN = 50005;
    const double eps = 1e-8;
    
    int n,stk[MAXN],top,p[MAXN],cnt,st;
    double ans=1e20;
    
    struct Node{
    	double x,y;
    	Node(double _x=0,double _y=0) {x=_x;y=_y;}
    }node[MAXN],point[5];
    
    Node operator-(Node A,Node B){return Node(A.x-B.x,A.y-B.y);}
    Node operator+(Node A,Node B){return Node(A.x+B.x,A.y+B.y);}
    Node operator*(Node A,double k){return Node(A.x*k,A.y*k);}
    inline double dot(Node A,Node B){return A.x*B.x+A.y*B.y;}
    inline double cross(Node A,Node B){return A.x*B.y-A.y*B.x;}
    inline int dcmp(double x){if(fabs(x)<=eps) return 0;return x>0?1:-1;}
    inline bool cmp(Node A,Node B){return A.x==B.x?A.y<B.y:A.x<B.x;}
    inline double check(int a,int b,int c){return cross(node[a]-node[b],node[c]-node[a]);}
    inline double dis(Node A,Node B){return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}
    inline double calc(int a,int b,int c){return cross(node[c]-node[a],node[c]-node[b]);}
    
    inline void rotating(){
    	p[cnt+1]=p[1];double Dis,L,R,H,tmp;
    	for(int i=1,a=2,b=2,c;i<=cnt;i++){
    		while(dot(node[p[a+1]]-node[p[i+1]],node[p[i]]-node[p[i+1]])
    			<=dot(node[p[a]]-node[p[i+1]],node[p[i]]-node[p[i+1]]))
    			a=(a==cnt)?1:a+1;
    		while(fabs(calc(p[i],p[i+1],p[b]))<=fabs(calc(p[i],p[i+1],p[b+1]))) 
    			b=(b==cnt)?1:b+1;
    		if(i==1) c=a;
    		while(dot(node[p[c+1]]-node[p[i]],node[p[i+1]]-node[p[i]])
    			<=dot(node[p[c]]-node[p[i]],node[p[i+1]]-node[p[i]]))
    			c=(c==cnt)?1:c+1;
    		Dis=dis(node[p[i]],node[p[i+1]]);
    		L=fabs(dot(node[p[c]]-node[p[i+1]],node[p[i]]-node[p[i+1]]))/Dis;
    		R=fabs(dot(node[p[a]]-node[p[i]],node[p[i+1]]-node[p[i]]))/Dis;
    		H=fabs(calc(p[i],p[i+1],p[b]))/Dis;
    		tmp=(L+R-Dis)*H;
    		if(tmp<ans){
    			ans=tmp;
    			point[1]=node[p[i+1]]-(node[p[i+1]]-node[p[i]])*(L/Dis);
    			point[2]=point[1]+(node[p[i+1]]-node[p[i]])*((R+L-Dis)/Dis);
    			point[3]=point[2]+(node[p[a]]-point[2])*(H/dis(node[p[a]],point[2]));
    			point[4]=point[3]+(node[p[i]]-node[p[i+1]])*((R+L-Dis)/Dis);
    		}
    	}
    }
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lf%lf",&node[i].x,&node[i].y);
    	sort(node+1,node+1+n,cmp);
    	for(int i=1;i<=n;i++){
    		while(top>1 && dcmp(check(stk[top],stk[top-1],i))!=1) top--;	
    		stk[++top]=i;
    	}top--;
    	for(int i=1;i<=top;i++) p[++cnt]=stk[i];top=0;
    	for(int i=n;i;i--){
    		while(top>1 && dcmp(check(stk[top],stk[top-1],i))!=1) top--;
    		stk[++top]=i;	
    	}top--;
    	for(int i=1;i<=top;i++) p[++cnt]=stk[i];
    	rotating();printf("%.5lf
    ",ans);point[st].y=1e20;
    	for(int i=1;i<=4;i++){
    		if(fabs(point[i].x)<eps) point[i].x=0;
    		if(fabs(point[i].y)<eps) point[i].y=0;	
    	}
    	for(int i=1;i<=4;i++)
    		if((point[i].y<point[st].y) || (point[i].y==point[st].y && point[i].x<point[st].x)) 
    			st=i;
    	printf("%.5lf %.5lf
    ",point[st].x,point[st].y);
    	for(int i=0;i<3;i++)
    		printf("%.5lf %.5lf
    ",point[(i+st)%4+1].x,point[(i+st)%4+1].y);
    	return 0;
    }
    
  • 相关阅读:
    Qt多表格滚动条同步
    Trie树
    计算机网络笔记--网络层--ICMP协议
    计算机网络笔记--网络层--NAT
    计算机网络笔记--IP地址
    计算机网络笔记--网络层--ARP协议
    计算机网络笔记--网络层1IP协议
    const与指针
    c/c++笔记--指向数组的指针与二维数组
    机试笔记9--二叉树的遍历
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10144095.html
Copyright © 2011-2022 走看看