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;
    }
    
  • 相关阅读:
    关于求 p_i != i and p_i != i+1 的方案数的思考过程
    poj 3041 Asteroids 二分图最小覆盖点
    poj 1325 Machine Schedule 最小顶点覆盖
    poj 1011 Sticks 减枝搜索
    poj 1469 COURSES 最大匹配
    zoj 1516 Uncle Tom's Inherited Land 最大独立边集合(最大匹配)
    Path Cover (路径覆盖)
    hdu 3530 SubSequence TwoPoint单调队列维护最值
    zoj 1654 Place the Rebots 最大独立集转换成二分图最大独立边(最大匹配)
    poj 1466 Girls and Boys 二分图最大独立子集
  • 原文地址:https://www.cnblogs.com/dd-bond/p/13540659.html
Copyright © 2011-2022 走看看