zoukankan      html  css  js  c++  java
  • 【算法学习笔记】36.凸包 求最大两点距离 SJTU OJ 1244 Date A Live

    Description

    某助教有好多好多妹纸,其中不乏来自五道口与东川路等男子职业技术学校的。然而,遥远的距离让他不得不花费大量的时间奔波于众多城市之间。为了更好地安排自己的约会计划,他想知道最远的两只妹纸之间的距离是多少。

    Input Format

    第一行有一个整数n,表示妹纸的数量。

    接下来n行,每行两个实数x,y,表示妹纸的坐标(假定在一个平面直角坐标系上)。

    对于80%的数据,n<=2000

    对于90%的数据,n<=10000

    对于100%的数据,n<=100000

    Output Format

    输出一个实数,表示最远的妹纸间的欧几里得距离(即直线距离)。答案保留4位小数。

    Sample Input

    3
    1 1
    0 0
    10 1
    

    Sample Output

    10.0499

    数学模型就是求一个点集最远两个点的距离大小.

    想法是先用Graham扫描法来建立凸包集合.
    然后有两条路,其中一个就是Cn2枚举出任意两个点 求出距离
    另一个是用传说中的旋转卡壳法来求.复杂度为On ,基本思想就是旋转寻找和凸包之边的最远的点,由于凸包的凸性质,导致这个最远点的旋转方向和边的旋转方向一致,所以压缩至On

    以下代码是用数组实现的凸包+Cn2方法,
    数组实现比STL的vector要快很多,而且也比较容易看懂.
    几个值得注意的地方是
    1.基点的选择, 选择最左下的点,还是选最低点里偏左的
    2.比较的方法, 余弦定理还是外积判断?
    3.栈顶指针的竖直和栈长度的关系...= =


    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #include <cstdio> 
    
    using namespace std; 
    struct Point
    {
        double x, y;
    };
     
    Point pointSet[100005];
    int convexHull[100005];//凸包只要存储点的ID即可
    int ps_len=0;//点集的大小
    int ch_len=0;//凸包的栈指针
    
    ostream& operator << (ostream &out, const Point& p) {
        out <<'('<<p.x<<','<<p.y<<')'<<endl ;
        return out;
    }
    
    //计算外积 负表示顺时针 正表示逆时针 0表示共线
    inline double crossProduct(const Point &p1, const Point &p2,const Point &p0){
        return (p1.x-p0.x)*(p2.y-p0.y) - (p1.y-p0.y)*(p2.x-p0.x);
    }
    
    //返回正数表示要把两个数进行交换 也就是把b放在a前面 逆时针排序
    int cmpTwoPoints(const void *a, const void *b){
        Point* p1 = (Point*) a;
        Point* p2 = (Point*) b;
        //注意:此时基点已经是pointSet[0]
        //第一种方法利用余弦定理来进行判断
        //第二种方法利用叉乘来表示 如果 < p0,p1 , p0,p2 >是负数 则表示指向纸面内部 也就是顺时针
        double res = crossProduct(*p1, *p2, pointSet[0]);
        if(res<0)
            return 1;
        if(res == 0 and p2->x < p1->x)//如果共线且p2更近
            return 1;
        return -1;
    }
    
    
    // inline Point CH(int CHid)
    // {
    //     return pointSet[convexHull[CHid]];
    // }
    
    //建立凸包
    void BuildConvexHull(){
        //Step1 找到基准点 最下偏左的点
        int basePoint=0;
        for (int i = 1; i < ps_len; ++i)
        {
            //if(    pointSet[i].y < pointSet[basePoint].y or (pointSet[i].y==pointSet[basePoint].y and pointSet[i].x<pointSet[basePoint].x) )
            if(    pointSet[i].x < pointSet[basePoint].x or (pointSet[i].x==pointSet[basePoint].x and pointSet[i].y<pointSet[basePoint].y) )
                basePoint = i;
        }
        swap(pointSet[basePoint],pointSet[0]);//把基点换到ps的第一个位置
        
        //Step2 把pointSet里的点按照他们与基点的连线与x轴的夹角的大小进行排序
        qsort(pointSet+1,ps_len-1,sizeof(Point),cmpTwoPoints);//不算基点 进行排序
       // PrintPS();
        //Step3 开始build凸包
        convexHull[0] = 0;//基点肯定是凸包上的第一个点 入栈
        convexHull[1] = 1;//预设第一个非基点的点也是凸包上的点  入栈
        convexHull[2] = 2;
        ch_len = 2;//指针指向栈顶元素
        //开始DFS --> 栈
        
        for (int i = 3; i < ps_len ; ++i)//研究剩余的所有点
        { 
            //假如让它入栈 它可以和 前一个点 前前一个点 是逆时针旋转的 那么就暂时可以加入 否则 踢出上x个点 直到可以继续
            while(ch_len > 0 and crossProduct(pointSet[convexHull[ch_len]],pointSet[i],pointSet[convexHull[ch_len-1]]) < 0)
                ch_len--;//抛弃这个凹点
            convexHull[++ch_len] = i;//暂时让此点入栈
        } 
    }
    
    inline double _dis(Point p1, Point p2){
        return sqrt(pow((p1.x-p2.x),2)+pow((p1.y-p2.y),2));
    }
    inline double _max(double a,double b){
        return a>b ? a : b;
    }
    
    double Cal(){
        double res = 0;
        for (int i = 0; i < ch_len+1-1; ++i) 
            for (int j = i+1; j < ch_len+1 ; ++j) 
                res = _max(res,_dis(pointSet[convexHull[i]],pointSet[convexHull[j]])); 
        return res;
    }
    int main(int argc, char const *argv[])
    {
        cin>>ps_len;
        for (int i = 0; i < ps_len; ++i)
            scanf("%lf %lf",&pointSet[i].x,&pointSet[i].y);  
        BuildConvexHull();
        printf("%.4lf",Cal());
        return 0;
    }
    View Code

    几个相关博客:

    http://www.cnblogs.com/devymex/archive/2010/08/09/1795392.html

    http://blog.csdn.net/hackbuteer1/article/details/7484746






  • 相关阅读:
    windows 查看端口被占用
    IOC控制反转
    spring配置,spring中的bean 的id不能相同
    prototype 用法
    js闭包用法
    struts2异常处理,global-results定义全局结果处理
    struts2中错误处理
    Struts2配置细节
    hql查询语句 内存中的情况,fetch迫切查询关键字
    Spring cloud微服务安全实战-4-5搭建OAuth2认证服务器
  • 原文地址:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1244.html
Copyright © 2011-2022 走看看