• 旋转卡壳


    4.1  求解平面最远点对(POJ 2187 Beauty Contest) 
    struct Point 
    { 
        int x,y; 
        Point(int _x = 0,int _y = 0) 
        { 
            x = _x; y = _y; 
        } 
        Point operator -(const Point &b)const 
        { 
            return Point(x - b.x, y - b.y); 
        } 
        int operator ^(const Point &b)const 
        { 
            return x*b.y - y*b.x; 
        } 
        int operator *(const Point &b)const 
        { 
            return x*b.x + y*b.y; 
        } 
        void input() 
        { 
            scanf("%d%d",&x,&y); 
        } 
    }; 
    //距离的平方 
    int dist2(Point a,Point b) 
    { 
        return (a-b)*(a-b); 
    } 
    //******二维凸包,int*********** 
    const int MAXN = 50010; 
    Point list[MAXN]; 
    int Stack[MAXN],top; 
    bool _cmp(Point p1,Point p2) 
    { 
        int tmp = (p1-list[0])^(p2-list[0]); 
        if(tmp > 0)return true; 
        else if(tmp == 0 && dist2(p1,list[0]) <= dist2(p2,list[0])) 
            return true; 
        else return false; 
    } 
    void Graham(int n) 
    { 
        Point p0; 
        int k = 0; 
        p0 = list[0]; 
        for(int i = 1;i < n;i++) 
            if(p0.y > list[i].y || (p0.y == list[i].y && p0.x > list[i].x)) 
            { 
                p0 = list[i]; 
                k = i; 
            } 
        swap(list[k],list[0]); 
        sort(list+1,list+n,_cmp); 
        if(n == 1) 
        { 
            top = 1; 
            Stack[0] = 0; 
            return; 
        } 
        if(n == 2) 
        { 
            top = 2; 
            Stack[0] = 0; Stack[1] = 1; 
            return; 
        } 
        Stack[0] = 0; Stack[1] = 1; 
        top = 2; 
        for(int i = 2;i < n;i++) 
        { 
            while(top > 1 && 
    ((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0) 
                top--; 
            Stack[top++] = i; 
        } 
    } 
    //旋转卡壳,求两点间距离平方的最大值 
    int rotating_calipers(Point p[],int n) 
    { 
        int ans = 0; 
        Point v; 
        int cur = 1; 
        for(int i = 0;i < n;i++) 
        { 
            v = p[i]-p[(i+1)%n]; 
            while((v^(p[(cur+1)%n]-p[cur])) < 0) 
                cur = (cur+1)%n; 
            ans = max(ans,max(dist2(p[i],p[cur]),dist2(p[(i+1)%n],p[(cur+1)%n])));  
        } 
        return ans; 
    } 
    Point p[MAXN]; 
    int main() 
    { 
        int n; 
        while(scanf("%d",&n) == 1) 
        { 
            for(int i = 0;i < n;i++)list[i].input(); 
            Graham(n); 
            for(int i = 0;i < top;i++)p[i] = list[Stack[i]]; 
            printf("%d
    ",rotating_calipers(p,top)); 
        } 
        return 0; 
    } 
    4.2  求解平面点集最大三角形 
    //旋转卡壳计算平面点集最大三角形面积 
    int rotating_calipers(Point p[],int n) 
    { 
        int ans = 0; 
        Point v; 
        for(int i = 0;i < n;i++) 
        { 
            int j = (i+1)%n; 
            int k = (j+1)%n; 
            while(j != i && k != i) 
            { 
                ans = max(ans,abs((p[j]-p[i])^(p[k]-p[i]))); 
                while( ((p[i]-p[j])^(p[(k+1)%n]-p[k])) < 0 ) 
                    k = (k+1)%n; 
                j = (j+1)%n; 
            } 
        } 
        return ans; 
    } 
    Point p[MAXN]; 
    int main() 
    { 
        int n; 
        while(scanf("%d",&n) == 1) 
        { 
            if(n == -1)break; 
            for(int i = 0;i < n;i++)list[i].input(); 
            Graham(n); 
            for(int i = 0;i < top;i++)p[i] = list[Stack[i]]; 
            printf("%.2f
    ",(double)rotating_calipers(p,top)/2); 
        } 
        return 0; 
    } 
    4.3  求解两凸包最小距离(POJ 3608) 
    const double eps = 1e-8; 
    int sgn(double x) 
    { 
        if(fabs(x) < eps)return 0; 
        if(x < 0)return -1; 
        else return 1; 
    } 
    struct Point 
    { 
        double x,y; 
        Point(double _x = 0,double _y = 0) 
        { 
            x = _x; y = _y; 
        } 
        Point operator -(const Point &b)const 
        { 
            return Point(x - b.x, y - b.y); 
        } 
        double operator ^(const Point &b)const 
        { 
            return x*b.y - y*b.x; 
        } 
        double operator *(const Point &b)const 
        { 
            return x*b.x + y*b.y; 
        } 
        void input() 
        { 
            scanf("%lf%lf",&x,&y); 
        } 
    }; 
    struct Line 
    { 
        Point s,e; 
        Line(){} 
        Line(Point _s,Point _e) 
        { 
            s = _s; e = _e; 
        } 
    }; 
    //两点间距离 
    double dist(Point a,Point b) 
    { 
        return sqrt((a-b)*(a-b)); 
    } 
    //点到线段的距离,返回点到线段最近的点 
    Point NearestPointToLineSeg(Point P,Line L) 
    { 
        Point result; 
        double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s)); 
        if(t >=0 && t <= 1) 
        { 
            result.x = L.s.x + (L.e.x - L.s.x)*t; 
            result.y = L.s.y + (L.e.y - L.s.y)*t; 
        } 
        else 
        { 
            if(dist(P,L.s) < dist(P,L.e)) 
                result = L.s; 
            else result = L.e; 
        } 
        return result; 
    } 
     
    /* 
     * 求凸包,Graham算法 
     * 点的编号0~n-1 
     * 返回凸包结果Stack[0~top-1]为凸包的编号 
     */ 
    const int MAXN = 10010; 
    Point list[MAXN]; 
    int Stack[MAXN],top; 
    //相对于list[0]的极角排序 
    bool _cmp(Point p1,Point p2) 
    { 
      double tmp = (p1-list[0])^(p2-list[0]); 
      if(sgn(tmp) > 0)return true; 
      else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0) 
        return true; 
      else return false; 
    } 
    void Graham(int n) 
    { 
      Point p0; 
      int k = 0; 
      p0 = list[0]; 
      //找最下边的一个点 
      for(int i = 1;i < n;i++) 
      { 
        if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) ) 
        { 
          p0 = list[i]; 
          k = i; 
        } 
      } 
      swap(list[k],list[0]); 
      sort(list+1,list+n,_cmp); 
      if(n == 1) 
      { 
        top = 1; 
        Stack[0] = 0; 
        return; 
      } 
      if(n == 2) 
      { 
        top = 2; 
        Stack[0] = 0; 
        Stack[1] = 1; 
        return ; 
      } 
      Stack[0] = 0; 
      Stack[1] = 1; 
      top = 2; 
      for(int i = 2;i < n;i++) 
      { 
        while(top > 1 && 
    sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 
    0) 
          top--; 
        Stack[top++] = i; 
      } 
    } 
    //点p0到线段p1p2的距离 
    double pointtoseg(Point p0,Point p1,Point p2) 
    { 
        return dist(p0,NearestPointToLineSeg(p0,Line(p1,p2))); 
    } 
    //平行线段p0p1和p2p3的距离 
    double dispallseg(Point p0,Point p1,Point p2,Point p3) 
    { 
        double ans1 = min(pointtoseg(p0,p2,p3),pointtoseg(p1,p2,p3)); 
        double ans2 = min(pointtoseg(p2,p0,p1),pointtoseg(p3,p0,p1)); 
        return min(ans1,ans2); 
    } 
    //得到向量a1a2和b1b2的位置关系 
    double Get_angle(Point a1,Point a2,Point b1,Point b2) 
    { 
        return (a2-a1)^(b1-b2); 
    } 
    double rotating_calipers(Point p[],int np,Point q[],int nq) 
    { 
        int sp = 0, sq = 0; 
        for(int i = 0;i < np;i++) 
            if(sgn(p[i].y - p[sp].y) < 0) 
                sp = i; 
        for(int i = 0;i < nq;i++) 
            if(sgn(q[i].y - q[sq].y) > 0) 
                sq = i; 
        double tmp; 
        double ans = dist(p[sp],q[sq]); 
        for(int i = 0;i < np;i++) 
        { 
            while(sgn(tmp = Get_angle(p[sp],p[(sp+1)%np],q[sq],q[(sq+1)%nq])) < 0)  
                sq = (sq+1)%nq; 
            if(sgn(tmp) == 0) 
                ans = min(ans,dispallseg(p[sp],p[(sp+1)%np],q[sq],q[(sq+1)%nq]));  
            else ans = min(ans,pointtoseg(q[sq],p[sp],p[(sp+1)%np])); 
            sp = (sp+1)%np; 
        } 
        return ans; 
    } 
    double solve(Point p[],int n,Point q[],int m) 
    { 
        return min(rotating_calipers(p,n,q,m),rotating_calipers(q,m,p,n)); 
    } 
    Point p[MAXN],q[MAXN]; 
    int main() 
    { 
        int n,m; 
        while(scanf("%d%d",&n,&m) == 2) 
        { 
            if(n == 0 && m == 0)break; 
            for(int i = 0;i < n;i++) 
                list[i].input(); 
            Graham(n); 
            for(int i = 0;i < top;i++) 
                p[i] = list[i]; 
            n = top; 
            for(int i = 0;i < m;i++) 
                list[i].input(); 
            Graham(m); 
            for(int i = 0;i < top;i++) 
                q[i] = list[i]; 
            m = top; 
            printf("%.4f
    ",solve(p,n,q,m)); 
        } 
        return 0; 
    } 
  • 相关阅读:
    网站如何做分布式(集群)的大纲
    [转]Bind和Eval的区别详解
    SQL 中游标的并发问题。
    如何利用客户端缓存对网站进行优化?
    Windows的第五种群集方案 CCS
    ICollection 接口的类序列化的问题。
    如何提高网页的效率(上篇)——提高网页效率的14条准则
    石油地质名称解释
    【SQL基础概念】
    DataView/DataRowView
  • 原文地址:https://www.cnblogs.com/xzxl/p/7247651.html
Copyright © 2020-2023  润新知