• 最小圆覆盖 hdu 3007


    今天学习了一下最小圆覆盖, 看了一下午都没看懂, 晚上慢慢的摸索这代码,接合着别人的讲解, 画着图跟着代码一步一步的走着,竟然有些理解了.

    最小圆覆盖: 给定n个点, 求出半径最小的圆可以把这些点全部包围, 可以在圆的边界上

    下面是我的个人理解. 如果不对, 还请路过大牛指出

      先找一个点, 让圆心等于这个点的坐标, 半径等于0, 显然这个对的, 接着找下一个点, 如果只有两个点的话, 那么最小的圆一定是以他们为直径做圆, 接着找第三个点, 如果第三个点在园内或者在边界上, 那么不用更新当前的最小圆, 如果不在的话, 就要更新当前的最小圆了,使它包括这三个点, 那么更新的办法就是从他开始做圆, 依次判断它前面的点是否满足在最小圆内, 如果不在的话, 就需要根据两个点或者三个点来确定圆了, 它的外接圆最多三个点就确定了,刚开始一直不理解这个为什么三个点,后来画画图,走走就出来了. 我这可能说的比较笼统. 表达能力太差. 还是把大牛的原话拷过来把.

    最小覆盖圆, 增量法
    假设圆O是前i-1个点得最小覆盖圆,加入第i个点,如果在圆内或边上则什么也不做。否,新得到的最小覆盖圆肯定经过第i个点。
    然后以第i个点为基础(半径为0),重复以上过程依次加入第j个点,若第j个点在圆外,则最小覆盖圆必经过第j个点。
    重复以上步骤(因为最多需要三个点来确定这个最小覆盖圆,所以重复三次)。遍历完所有点之后,所得到的圆就是覆盖所有点得最小圆。

    证明可以考虑这么做:
    最小圆必定是可以通过不断放大半径,直到所有以任意点为圆心,半径为半径的圆存在交点,此时的半径就是最小圆。所以上述定理可以通过这个思想得到。这个做法复杂度是O(n)的,当加入圆的顺序随机时,因为三点定一圆,所以不在圆内概率是3/i,求出期望可得是O(n)。

    下面是代码(模板)

    /*************************************************************************
        > File Name:            hdu_3007.cpp
        > Author:               Howe_Young
        > Mail:                 1013410795@qq.com
        > Created Time:         2015年05月04日 星期一 18时42分33秒
     ************************************************************************/
    /*最小圆覆盖*/
    /*给定n个点, 让求半径最小的圆将n个点全部包围,可以在圆上*/
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #define EPS 1e-8
    using namespace std;
    const int maxn = 550;
    struct point{
        double x, y;
    };
    int sgn(double x)
    {
        if (fabs(x) < EPS)
            return 0;
        return x < 0 ? -1 : 1;
    }
    double get_distance(const point a, const point b)//两点之间的距离
    { 
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 
    }
    point get_circle_center(const point a, const point b, const point c)//得到三角形外接圆的圆心
    {
        point center;
        double a1 = b.x - a.x;
        double b1 = b.y - a.y;
        double c1 = (a1 * a1 + b1 * b1) / 2.0;
        double a2 = c.x - a.x;
        double b2 = c.y - a.y;
        double c2 = (a2 * a2 + b2 * b2) / 2.0;
        double d = a1 * b2 - a2 * b1;
        center.x = a.x + (c1 * b2 - c2 * b1) / d;
        center.y = a.y + (a1 * c2 - a2 * c1) / d;
        return center;
    }
    //p表示定点, n表示顶点的个数, c代表最小覆盖圆圆心, r是半径
    void min_cover_circle(point *p, int n, point &c, double &r)//找最小覆盖圆(这里没有用全局变量p[], 因为是为了封装一个函数便于调用)
    {
        random_shuffle(p, p + n);//随机函数,使用了之后使程序更快点,也可以不用
        c = p[0];
        r = 0;
        for (int i = 1; i < n; i++)
        {
            if (sgn(get_distance(p[i], c) - r) > 0)//如果p[i]在当前圆的外面, 那么以当前点为圆心开始找
            {
                c = p[i];//圆心为当前点
                r = 0;//这时候这个圆只包括他自己.所以半径为0
                for (int j = 0; j < i; j++)//找它之前的所有点
                {
                    if (sgn(get_distance(p[j], c) - r) > 0)//如果之前的点有不满足的, 那么就是以这两点为直径的圆
                    {
                        c.x = (p[i].x + p[j].x) / 2.0;
                        c.y = (p[i].y + p[j].y) / 2.0;
                        r = get_distance(p[j], c);
                        for (int k = 0; k < j; k++)
                        {
                            if (sgn(get_distance(p[k], c) - r) > 0)//找新作出来的圆之前的点是否还有不满足的, 如果不满足一定就是三个点都在圆上了
                            {
                                c = get_circle_center(p[i], p[j], p[k]);
                                r = get_distance(p[i], c);
                            }
                        }
                    }
                }
            }
        }
    }
    int main()
    {
        int n;
        point p[maxn];
        point c; double r;
        while (~scanf("%d", &n) && n)
        {
            for (int i = 0; i < n; i++)
                scanf("%lf %lf", &p[i].x, &p[i].y);
            min_cover_circle(p, n, c, r);
            printf("%.2lf %.2lf %.2lf
    ", c.x, c.y, r);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    c#类的小小理解
    sql语句:保留要害字的问题.例如 size,text,user等
    c#2005做新闻发布系统心得
    asp 遇到过的问题集锦,附加asp语句添加数据库和生成表,asp命令更改指定文件的文件名,asp值传递的应用091116小结
    dropdownlist控件失去焦点的小应用和函数substr
    获得当前应用程序路径C#03
    模糊查询简单分析,得出sql语句
    20080905经典的DataReader对象解读+几种对数据库的操作的命令,20100111update read db example
    Servlet 容器的工作原理 ( 二 )
    手低眼高 初学者学习Hibernate的方法
  • 原文地址:https://www.cnblogs.com/Howe-Young/p/4477550.html
Copyright © 2020-2023  润新知