zoukankan      html  css  js  c++  java
  • HDU 6882 Divide and Conquer(二分)

    题面

    (使用两条相交直线平分n个点,使得每块区域都包含frac{n}{4}个点,保证n\%4equiv0)

    Solution

    首先我们可以明确此题一定是有解的,所以我们可以首先固定一条平分线再去寻找第二条平分线,那么第一条平分线我们可以通过将所有点按照(x,y)排序,选取中间([frac{n}{2}-1]和[frac{n}{2}])两个点,选取一条斜率接近(frac{pi}{2})的直线平分即可,那么第二条线的斜率就是在([-frac{pi}{2},frac{pi}{2}])之间,我们需要找到这样一条直线满足和第一条直线恰好平分一侧的(frac{n}{2})个点,我们可以发现这条直线的斜率是可以进行二分的,我们可以将每个点按照此斜率投射到之前第一条直线上,排序后直接可以遍历记录左侧点和右侧点的个数,如果一侧点不够(frac{n}{2}另一侧点多于frac{n}{2})个点,那么我们可以将斜率往点少的一侧倾斜即可,最后可以得到恰好平分的斜率以及那个平分位置前一个点,那么直接将一条直接经过该点并平行上一丢丢距离就可以完成构造,总体复杂度({O(nlog^2n)})

    //      ——By DD_BOND
    
    //#include<bits/stdc++.h>
    //#include<unordered_map>
    //#include<unordered_set>
    #include<functional>
    #include<algorithm>
    #include<iostream>
    //#include<ext/rope>
    #include<iomanip>
    #include<climits>
    #include<cstring>
    #include<cstdlib>
    #include<cstddef>
    #include<cstdio>
    #include<memory>
    #include<vector>
    #include<cctype>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<ctime>
    #include<stack>
    #include<map>
    #include<set>
    
    #define fi first
    #define se second
    #define pb push_back
    #define MP make_pair
    
    //#pragma GCC optimize(3)
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    
    using namespace std;
    
    typedef double db;
    typedef long long ll;
    typedef pair<db,db> Pd;
    typedef pair<int,int> P;
    typedef pair<ll,ll> Pll;
    
    const db eps=1e-8;
    const int MAXN=1e3+10;
    const db pi=acos(-1.0);
    const ll INF=0x3f3f3f3f3f3f3f3f;
    
    inline int dcmp(db x){
        if(fabs(x)<eps) return 0;
        return (x>0? 1: -1);
    }
    
    inline db Sqrt(db x){
        return x>0? sqrt(x): 0;
    }
    
    inline db sqr(db x){ return x*x; }
    
    struct Point{
        db x,y;
        Point(){ x=0,y=0; }
        Point(db _x,db _y):x(_x),y(_y){}
        void input(){
            double _x,_y;
            scanf("%lf%lf",&_x,&_y); 
            x=_x,y=_y;
        }
        bool operator <(const Point &b)const{
            return (dcmp(x-b.x)==0? dcmp(y-b.y)<0 : x<b.x);
        }
        db operator ^(const Point &b)const{     //叉积 
            return x*b.y-y*b.x;
        }
        db operator *(const Point &b)const{     //点积
            return x*b.x+y*b.y;
        }
        Point operator +(const Point &b)const{
            return Point(x+b.x,y+b.y);
        }
        Point operator -(const Point &b)const{
            return Point(x-b.x,y-b.y);
        }
        Point operator *(db a){
            return Point(x*a,y*a);
        }
        Point operator /(db a){
            return Point(x/a,y/a);
        }
    };
    
    inline db cross(Point a,Point b){   //叉积        
        return a.x*b.y-a.y*b.x;
    }
    
    inline db dot(Point a,Point b){ //点积        
        return a.x*b.x+a.y*b.y;
    }
    
    struct Line{
        Point s,e;
        Line(){}
        Line(Point _s,Point _e):s(_s),e(_e){} //两点确定直线
        db polar(){ //极角
            return atan2(e.y-s.y,e.x-s.x);   //返回与x轴正向夹角(-pi~pi]
        }
    };
    
    Point line_intersection(Line a,Line v){ //直线交点  调用前确保有交点
        db a1=cross(v.e-v.s,a.s-v.s);
        db a2=cross(v.e-v.s,a.e-v.s);
        return Point((a.s.x*a2-a.e.x*a1)/(a2-a1),(a.s.y*a2-a.e.y*a1)/(a2-a1));
    }
    
    
    Line l1,l2;
    Point point[50010];
    pair<db,int>st[50010];
    
    int main(void){
        int t;  scanf("%d",&t);
        while(t--){
            int n;  scanf("%d",&n);
            for(int i=0;i<n;i++)    point[i].input();
            sort(point,point+n);
            if(point[n/2-1].x==point[n/2].x){
                int sum=point[n/2-1].y+point[n/2].y;
                l1=Line(Point(point[n/2].x-1,-9e8+sum/2),Point(point[n/2].x+1,9e8+sum/2+(sum%2)));
            }
            else    l1=Line(Point(point[n/2-1].x,-9e8),Point(point[n/2].x,9e8));
            int las=0;
            db l=l1.polar()-pi+eps,r=l1.polar()-eps,theta=-1;
            for(int t=1;t<=60;t++){
                int f=0;
                db mid=(l+r)/2;
                Point vec(1e6*cos(mid),1e6*sin(mid));
                for(int i=0;i<n;i++)    st[i]={line_intersection(l1,Line(point[i],point[i]+vec)).y,i};
                sort(st,st+n);
                for(int i=0,ls=0,rs=0;i<n;i++){
                    if(i){
                        if(dcmp(st[i-1].fi-st[i].fi)==0){
                            if(st[i].se<n/2)    ls++;
                            else                rs++;
                        }
                        else{
                            if(ls==n/4&&rs==n/4){ f=1,las=st[i-1].se,theta=mid; break; }
                            else if(ls>=n/4){ l=mid; break; }
                            else if(rs>=n/4){ r=mid; break; }
                            if(st[i].se<n/2)    ls++;
                            else                rs++;
                        }
                    }
                    else{
                        if(st[i].se<n/2)    ls++;
                        else                rs++;
                    }
                }
                if(f)   break;
            }
            l2=Line(point[las]+Point(9e8*cos(theta),9e8*sin(theta)),point[las]-Point(9e8*cos(theta),9e8*sin(theta)));
            printf("%d %d %d %d
    ",(int)round(l1.s.x),(int)round(l1.s.y),(int)round(l1.e.x),(int)round(l1.e.y));
            printf("%d %d %d %d
    ",(int)round(l2.s.x),(int)round(l2.s.y+0.9999),(int)round(l2.e.x),(int)round(l2.e.y+0.999));
        }
        return 0;
    }
    
  • 相关阅读:
    写一个精确定位异常的方法
    做一个牛XX的身份证号验证类(支持15位和18位)
    C#获取设备的IP和Mac类
    winfrom 倒计时控件
    一个实用价值很大的人脸关键点检测算法PFLD
    刷新WIDER Face纪录!TinaFace:人脸检测新网络,代码已开源!
    虚拟机安装教程
    python---文件路径的操作(有点意思)
    python_opencv -------->>>>>>>>>cv2.warpAffine()参数详解
    yolov5数据增强引发的思考——透视变换矩阵的创建
  • 原文地址:https://www.cnblogs.com/dd-bond/p/13540659.html
Copyright © 2011-2022 走看看