zoukankan      html  css  js  c++  java
  • poj 3608 旋转卡壳求不相交凸包最近距离;

    题目链接:http://poj.org/problem?id=3608

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int maxn = 10500;
    const int maxe = 100000;
    const int INF = 0x3f3f3f;
    const double eps = 1e-8;
    const double PI = acos(-1.0);
    
    struct Point{
        double x,y;
        Point(double x=0, double y=0) : x(x),y(y){ }    //构造函数
    };
    typedef Point Vector;
    
    Vector operator + (Vector A , Vector B){return Vector(A.x+B.x,A.y+B.y);}
    Vector operator - (Vector A , Vector B){return Vector(A.x-B.x,A.y-B.y);}
    Vector operator * (Vector A , double p){return Vector(A.x*p,A.y*p);}
    Vector operator / (Vector A , double p){return Vector(A.x/p,A.y/p);}
    
    bool operator < (const Point& a,const Point& b){
        return a.x < b.x ||( a.x == b.x && a.y < b.y);
    }
    
    int dcmp(double x){
        if(fabs(x) < eps) return 0;
        else              return x < 0 ? -1 : 1;
    }
    bool operator == (const Point& a, const Point& b){
        return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
    }
    
    ///向量(x,y)的极角用atan2(y,x);
    double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
    double Length(Vector A)    { return sqrt(Dot(A,A)); }
    double Angle(Vector A, Vector B)  { return acos(Dot(A,B) / Length(A) / Length(B)); }
    double Cross(Vector A, Vector B)  { return A.x*B.y - A.y * B.x; }
    
    Vector Rotate(Vector A, double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); }
    
    ///求点P到线段AB的距离,先看Q点在线段外还是内;利用点积就可以,
    double DistanceToSegment(Point P,Point A,Point B){
        if(A == B)  return Length(P-A);
        Vector v1 = B - A,v2 = P - A,v3 = P - B;
        if(dcmp(Dot(v1,v2)) < 0)       return Length(v2);
        else if(dcmp(Dot(v1,v3) > 0))  return Length(v3);
        else    return  fabs(Cross(v1,v2))/Length(v1);
    }
    ///求线段AB与线段CD的距离;
    double DistanceBetweenSegment(Point A,Point B,Point C,Point D){
        return min(min(DistanceToSegment(A,C,D),DistanceToSegment(B,C,D)),min(DistanceToSegment(C,A,B),DistanceToSegment(D,A,B)));
    }
    
    //凸包:
    /**Andrew算法思路:首先按照先x后y从小到大排序(这个地方没有采用极角逆序排序,所以要进行两次扫描),删除重复的点后得到的序列p1,p2.....,然后把p1和p2放到凸包中。从p3开始,当新的
    点在凸包“前进”方向的左边时继续,否则依次删除最近加入凸包的点,直到新点在左边;**/
    
    //Goal[]数组模拟栈的使用;
    int ConvexHull(Point* P,int n,Point* Goal){
        sort(P,P+n);
        int m = unique(P,P+n) - P;    //对点进行去重;
        int cnt = 0;
        for(int i=0;i<m;i++){       //求下凸包;
            while(cnt>1 && dcmp(Cross(Goal[cnt-1]-Goal[cnt-2],P[i]-Goal[cnt-2])) <= 0)  cnt--;
            Goal[cnt++] = P[i];
        }
        int temp = cnt;
        for(int i=m-2;i>=0;i--){     //逆序求上凸包;
            while(cnt>temp && dcmp(Cross(Goal[cnt-1]-Goal[cnt-2],P[i]-Goal[cnt-2])) <= 0) cnt--;
            Goal[cnt++] = P[i];
        }
        if(cnt > 1) cnt--;  //减一为了去掉首尾重复的;
        return cnt;
    }
    
    double solve(Point* P1,Point* Q1,int Minid,int Maxid,int N,int M){
        double temp,ret = 1e5;
        P1[N] = P1[0];    Q1[M] = Q1[0];
        for(int i=0;i<N;i++){
            while(temp = dcmp(Cross(Q1[Maxid]-Q1[Maxid+1],P1[Minid+1]-P1[Minid]))> 0)  //这一步最难理解:要理解怎样才能使Q1[Maxid]Q1[Maxid+1]这条线段最接近线段P1[Minid+1]P1[Minid];
                Maxid = (Maxid+1)%M;                    // 先以P1[Minid]为定点,旋转Q1[Maxid];
            if(temp < 0)  ret = min(ret,DistanceToSegment(Q1[Maxid],P1[Minid],P1[Minid+1]));
            else          ret = min(ret,DistanceBetweenSegment(P1[Minid],P1[Minid+1],Q1[Maxid],Q1[Maxid+1]));
            Minid = (Minid + 1)%N;                      //再旋转P1[Minid];
        }
        return ret;
    }
    Point read_point(){
        Point A;
        scanf("%lf %lf",&A.x,&A.y);
        return A;
    }
    
    /*******************************分割线******************************/
    Point P[maxn],Q[maxn];
    Point P1[maxn],Q1[maxn];  //利用凸包算法使坐标逆时针化后的存储;
    int N,M;
    int Maxid,Minid;
    
    void GetMaxandMin(int& Maxid,int& Minid){
        Maxid = 0;   Minid = 0;
        for(int i=1;i<N;i++){
            if(P1[i].y < P1[Minid].y)  Minid = i;
        }
        for(int i=1;i<M;i++){
            if(Q1[i].y > Q1[Maxid].y)  Maxid = i;
        }
    }
    
    int main()
    {
        //freopen("E:\acm\input.txt","r",stdin);
    
        while(cin>>N>>M && N+M){
            for(int i=0;i<N;i++)    P[i] = read_point();
            N = ConvexHull(P,N,P1);
    
            for(int i=0;i<M;i++)    Q[i] = read_point();
            M = ConvexHull(Q,M,Q1);
    
            GetMaxandMin(Maxid,Minid);
    
            double ans = solve(P1,Q1,Minid,Maxid,N,M);
            printf("%.5f
    ",ans);
        }
    }
    View Code
  • 相关阅读:
    2009年职工象棋比赛 第七轮 五七炮对屏风马
    2009年职工象棋比赛 第一轮 顺炮直车对横车
    给文件起个好名字是多么的重要!
    职工象棋比赛 第十一轮 仙人指路
    2009年职工象棋比赛 第八轮 顺炮横车对直车
    2009年职工象棋比赛 第三轮 中炮对反宫马
    2009年职工象棋比赛 第二轮 中炮对单提马
    终于记住了这两个词:devour、devout
    2009年职工象棋比赛 第四轮 顺炮直车对横车
    2009年职工象棋比赛 第五轮 中炮对右三步虎
  • 原文地址:https://www.cnblogs.com/acmdeweilai/p/3258673.html
Copyright © 2011-2022 走看看