最小圆覆盖问题。

题目描述

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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值