最小圆覆盖问题。

题目描述

An artist who wanted to create an installation where his works appeared to be floating in midair has cast a large cube of clear acrylic to serve as a base. Unfortunately, during the casting, some small flecks of dirt got into the mix, and now appear as a cluster of pinpoint flaws in the otherwise clear cube.

He wants to drill out the portion of the cube containing the flaws so that he can plug the removed volume with new, clear acrylic. He would prefer to do this in one drilling step. For stability’s sake, the drill must enter the cube only once, perpendicular to one of its faces. The cube’s faces are parallel to the coordinate axes.

Given the (x,y,z) positions of the flaws, and treating the size of the flaws as negligible, what is the smallest diameter drill bit that can be used to remove the flaws in one operation??

输入描述:

The first line of input contains an integer N denoting the number of flaws. 3≤N≤5000

This is followed by N lines of input, each containing three real numbers in the range −1000.0…1000.0, denoting the (x,y,z) coordinates of a single flaw. Each number contains at most 6 digits following a decimal point. The decimal point may be omitted if all succeeding digits are zero.

输出描述:

Print the diameter of the smallest drill bit that would remove all the flaws.The answer is considered correct if the absolute or relative error is less than 10-4

输入

8
435.249 -494.71 -539.356
455.823 -507.454 -539.257
423.394 -520.682 -538.858
446.507 -501.953 -539.37
434.266 -503.664 -560.631
445.059 -549.71 -537.501
449.65 -506.637 -513.778
456.05 -499.715 -561.329

输出

49.9998293198

题意:给你一些空间点坐标,要求设计一个钻头使得这个钻头只能垂直一个平面进入立方体零件一次,并且覆盖所有空间点坐标。
求钻头的最小直径。

思路:分为三种情况 ( x , y ) 平面、( x , z ) 平面、( y , z ) 平面,算出每一个平面的最小圆覆盖直径,找一个最小的即可。

首先最小圆覆盖是什么东东?直接上代码,推导一下就明白了。

最小圆覆盖的核心代码:

Node pan(double x1,double y1,double x2,double y2,double x3,double y3)//三角形的外接圆
{
    Node kk;
    double a1=x2-x1,b1=y2-y1,c1=(a1*a1+b1*b1)/2.0;
    double a2=x3-x1,b2=y3-y1,c2=(a2*a2+b2*b2)/2.0;
    double d=a1*b2-a2*b1;
    kk.x=x1+(c1*b2-c2*b1)/d;
    kk.y=y1+(a1*c2-a2*c1)/d;
    return kk;
}
double solve(Node a[])//最小圆覆盖
{
    Node o;
    o.x=a[1].x;
    o.y=a[1].y;
    double r=0;
    for(int i=2;i<=n;i++)
    {
        if(aa(o,a[i])>r)//第一个点为圆心
        {
            o.x=a[i].x,o.y=a[i].y;
            r=0;
            for(int j=1;j<i;j++)
            {
                if(aa(o,a[j])>r)第一个点和第二个点中点为圆心,距离为直径
                {
                    o.x=(a[i].x+a[j].x)/2.0;
                    o.y=(a[i].y+a[j].y)/2.0;
                    r=aa(o,a[j]);
                    for(int k=1;k<j;k++)
                    {
                        if(aa(o,a[k])>r)//三点确定一个圆
                        {
                            o=pan(a[i].x,a[i].y,a[j].x,a[j].y,a[k].x,a[k].y);
                            r=aa(o,a[k]);
                        }
                    }
                }
            }
        }
    }
    return r;
}

本题的AC代码:

#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
int n;
struct node
{
    double x,y,z;
} q[50100];
struct Node
{
    double x,y;
}w[50100],o;
double aa(Node a,Node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
Node pan(double x1,double y1,double x2,double y2,double x3,double y3)//三角形的外接圆
{
    Node kk;
    double a1=x2-x1,b1=y2-y1,c1=(a1*a1+b1*b1)/2.0;
    double a2=x3-x1,b2=y3-y1,c2=(a2*a2+b2*b2)/2.0;
    double d=a1*b2-a2*b1;
    kk.x=x1+(c1*b2-c2*b1)/d;
    kk.y=y1+(a1*c2-a2*c1)/d;
    return kk;
}
double solve(Node a[])//最小圆覆盖
{
    Node o;
    o.x=a[1].x;
    o.y=a[1].y;
    double r=0;
    for(int i=2;i<=n;i++)
    {
        if(aa(o,a[i])>r)//第一个点为圆心
        {
            o.x=a[i].x,o.y=a[i].y;
            r=0;
            for(int j=1;j<i;j++)
            {
                if(aa(o,a[j])>r)第一个点和第二个点中点为圆心,距离为直径
                {
                    o.x=(a[i].x+a[j].x)/2.0;
                    o.y=(a[i].y+a[j].y)/2.0;
                    r=aa(o,a[j]);
                    for(int k=1;k<j;k++)
                    {
                        if(aa(o,a[k])>r)//三点确定一个圆
                        {
                            o=pan(a[i].x,a[i].y,a[j].x,a[j].y,a[k].x,a[k].y);
                            r=aa(o,a[k]);
                        }
                    }
                }
            }
        }
    }
    return r;
}
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)scanf("%lf%lf%lf",&q[i].x,&q[i].y,&q[i].z);
    double hh=99999999.00;
    for(int i=1;i<=n;i++){w[i].x=q[i].x,w[i].y=q[i].y;}hh=min(hh,solve(w));
    for(int i=1;i<=n;i++){w[i].x=q[i].x,w[i].y=q[i].z;}hh=min(hh,solve(w));
    for(int i=1;i<=n;i++){w[i].x=q[i].y,w[i].y=q[i].z;}hh=min(hh,solve(w));
    printf("%.10f\n",2*hh);
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最小覆盖问题是一个经典的几何优化问题,其求解模型可以通过以下几种方法来实现: 1. Welzl算法:Welzl算法是一种递归的随机增量算法,用于寻找最小覆盖。该算法的基本思想是通过随机选择点,逐步构建包含这些点的最小。具体步骤包括:如果点集为空,则返回空;如果只有一个点,则返回以该点为心、半径为0的;如果有两个点,则返回以这两个点为直径的;对于多于两个点的情况,随机选择一个点,递归构建包含其余点的最小,并检查是否需要更新最小。该算法的时间复杂度为O(n)。 2. Graham扫描算法:Graham扫描算法是一种基于极角排序的凸包算法,也可以用于解决最小覆盖问题。该算法首先选取一个点作为起始点,并按照与起始点的极角大小进行排序。然后维护一个栈,依次将点入栈,并检查是否需要进行凸包的调整。最后,使用Welzl算法对凸包上的点进行最小覆盖的求解。该算法的时间复杂度为O(nlogn)。 3. 随机增量算法:随机增量算法是一种启发式算法,通过随机增加点来逼近最小覆盖。该算法的基本步骤包括:选取初始,并将点集分为内点和外点;在外点中随机选择一个点,将其添加到内,更新最小;重复上述步骤,直到所有点都被添加到内。该算法的时间复杂度与点的数量有关。 以上是常见的几种模型用于解决最小覆盖问题。具体选择哪种模型取决于问题规模、时间限制和精度要求等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值