bzoj 1337 最小圆覆盖

bzoj 1337 最小圆覆盖

  • 补充一个求三角形外心的向量法.用了点积的几何意义,很实用.出处.

  • 使用随机增量法求.首先随机打乱顺序,然后三重循环,选择当前在圆外的点更新圆,分别按照 \(1/2/3\) 个点确定圆的方式更新即可.
  • 由于随机一个点不在前 \(i\) 个点的最小覆盖圆内的概率是 \(\frac 3 i\) ,可以证明这样的时间复杂度是 \(O(n)\) 的,这种做法可以推广到常数维度上,时间复杂度仍为 \(O(n)\) .
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
const double eps=1e-9;
const int MAXN=1e5+10;
int dcmp(double x)
{
    return fabs(x)<=eps?0:(x>0?1:-1);
}
struct v2{
    double x,y;
    v2(double x=0,double y=0):x(x),y(y) {}
    v2 operator + (const v2 &rhs) const
        {
            return v2(x+rhs.x,y+rhs.y);
        }
    v2 operator / (const double &rhs) const
        {
            return v2(x/rhs,y/rhs);
        }
    v2 operator - (const v2 &rhs) const
        {
            return v2(x-rhs.x,y-rhs.y);
        }
    double operator * (const v2 &rhs) const
        {
            return x*rhs.y-y*rhs.x;
        }
    double modulus()
        {
            return sqrt(x*x+y*y);
        }
};
double dist(v2 a,v2 b)
{
    return (a-b).modulus();
}
v2 CirCentre(v2 a,v2 b,v2 c)
{
    v2 centre;
    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;
    centre.x=a.x+(c1*b2-c2*b1)/d;
    centre.y=a.y+(a1*c2-a2*c1)/d;
    return centre;
}
bool incircle(v2 p,v2 centre,double r)
{
    return dcmp(dist(p,centre)-r)<=0;
}
void MinCircleCover(v2 *p,int n,v2 &centre,double &r)
{
    srand(time(NULL));
    random_shuffle(p+1,p+1+n);
    centre=p[1];
    r=0;
    for(int i=2;i<=n;++i)
        {
            if(!incircle(p[i],centre,r))
                {
                    centre=p[i];
                    r=0;
                    for(int j=1;j<i;++j)
                        {
                            if(!incircle(p[j],centre,r))
                                {
                                    centre=(p[i]+p[j])/2.0;
                                    r=(p[i]-p[j]).modulus()/2.0;
                                    for(int k=1;k<j;++k)
                                        {
                                            if(!incircle(p[k],centre,r))
                                                {
                                                    centre=CirCentre(p[i],p[j],p[k]);
                                                    r=dist(centre,p[i]);
                                                }
                                        }
                                }
                        }
                }
        }
}
int n;
v2 p[MAXN];
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    v2 centre;
    double r;
    MinCircleCover(p,n,centre,r);
    printf("%.3lf\n",r);
    return 0;
}

原文地址:https://www.cnblogs.com/jklover/p/10388841.html

时间: 2024-10-12 11:20:43

bzoj 1337 最小圆覆盖的相关文章

BZOJ 1337 最小圆覆盖 随机增量法

题意:链接 方法:随机增量法 解析: 首先把所有点打乱. 然后枚举第一个点,如果不在当前的圆内则把它设为圆心. 再枚举第二个点,如果不在当前的圆内则把圆设为其与第一个点的距离为直径的圆. 再枚举第三个点,如果不在当前的圆内则把圆设为这三个点构成三角形的外接圆. 然后最后就是答案了. 别问我这为什么是对的- -! 复杂度期望O(n),我是信了. 代码: #include <cmath> #include <cstdio> #include <iomanip> #inclu

bzoj2823: [AHOI2012]信号塔&amp;&amp;1336: [Balkan2002]Alien最小圆覆盖&amp;&amp;1337: 最小圆覆盖

首先我写了个凸包就溜了 这是最小圆覆盖问题,今晚学了一下 先随机化点,一个个加入 假设当前圆心为o,半径为r,加入的点为i 若i不在圆里面,令圆心为i,半径为0 再重新从1~i-1不停找j不在圆里面,令圆心为ij中点,直径为ij距离 再重新在1~j-1不停找k不在圆里面,三点可确定一圆,初中数学 复杂度看似O(n^3)实则O(n),好玄学 坑点:注意如果用点斜式表示方程有斜率为不存在的情况,需要特判 #include<cstdio> #include<iostream> #incl

【BZOJ-1336&amp;1337】Alie最小圆覆盖 最小圆覆盖(随机增量法)

1336: [Balkan2002]Alien最小圆覆盖 Time Limit: 1 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1573  Solved: 697[Submit][Status][Discuss] Description 给出N个点,让你画一个最小的包含所有点的圆. Input 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0) Outpu

Bzoj 1336&amp;1337 Alien最小圆覆盖

1336: [Balkan2002]Alien最小圆覆盖 Time Limit: 1 Sec  Memory Limit: 162 MBSec  Special Judge Submit: 1473  Solved: 648 [Submit][Status][Discuss] Description Input 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0) Output Sample Input 6 8.0

[BZOJ 3564] [SHOI2014] 信号增幅仪 【最小圆覆盖】

题目链接:BZOJ - 3564 题目分析 求最小椭圆覆盖,题目给定了椭圆的长轴与 x 轴正方向的夹角,给定了椭圆长轴与短轴的比值. 那么先将所有点旋转一个角度,使椭圆长轴与 x 轴平行,再将所有点的 x 坐标除以长轴与短轴的比值,然后就直接做最小圆覆盖了. 随机增量法,一定别忘了 random_shuffle . 代码 #include <iostream> #include <cstdlib> #include <cstring> #include <cstd

BZOJ 2823 AHOI 2012 信号塔 凸包+最小圆覆盖

题目大意:给出平面上n个点,求最小圆覆盖. 思路:圆覆盖问题只与所有点中凸包上的点有关,因此先求一下凸包,然后数据范围骤减.大概是只剩下logn左右个点.这样就可以随便浪了. 先找所有三个点组成的圆,然后找两个点为直径所组成的圆. 还有就是三角形的外心公式,简直不是人推的,然后我就机制的百度了,结果如下: 不要模拟退火... 样例很坑,当你算出2.49 2.86的时候,不要认为你被卡精了,其实是你写挂了... CODE: #include <cmath> #include <cstdio

【bzoj1336/1337/2823】[Balkan2002]Alien最小圆覆盖 随机增量法

题目描述 给出N个点,让你画一个最小的包含所有点的圆. 输入 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0) 输出 输出圆的半径,及圆心的坐标 样例输入 6 8.0 9.0 4.0 7.5 1.0 2.0 5.1 8.7 9.0 2.0 4.5 1.0 样例输出 5.00 5.00 5.00 题解 随机增量法求最小圆覆盖裸题 求法:设初始圆为某空圆,先枚举第一个点,如果不在当前圆内,则令当前圆为这一个点的最小圆

BZOJ 1336 Balkan2002 Alien最小圆覆盖

题目大意:最小圆覆盖. 思路:再拍一份模板.做法见:http://blog.csdn.net/jiangyuze831/article/details/43950601 CODE: #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring> #include <iomanip> #include <iostream> #include

BZOJ 3564 SHOI 2014 信号增幅仪 坐标变换+最小圆覆盖

题目大意:给出平面上的一些点,现在让你用一个长轴与x轴成一定角度的,长轴:短轴已知的椭圆来覆盖所有的坐标,求最小的短轴长度. 思路:很明显,这个椭圆的形状和放置状态已经给出了,但是没有办法求最小拖圆覆盖啊.采用坐标变换,将椭圆变成圆.首先我们先让长轴与x轴平行,将平面上的所有点都旋转这个角度.之后只需要让所有点的x坐标除以长轴:短轴就可以了.剩下的就是最小圆覆盖了. 注:坐标旋转公式: x' = x * cos(a) - y * sin(a) y' = x * sin(a) + y * cos(