hdu 2215(最小覆盖圆)

本文介绍了用于计算平面上最小覆盖圆及三维空间中最小覆盖球的算法实现。通过逐步迭代改进圆心位置来减少覆盖半径,适用于解决特定几何问题。
#include<stdio.h>  //最小覆盖圆模板。
#include<math.h>
#define maxn 502
struct ss
{
    double x,y;
};
ss a[maxn],d;
double r;
double dis(ss p1,ss p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double Cross(ss p1,ss p2,ss p3)  //叉积判断是否共线
{
    return (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x);
}
void mindis2(ss p,ss q,int n)
{
    d.x=(p.x+q.x)/2;
    d.y=(p.y+q.y)/2;
    r=dis(p,q)/2;
    double c1,c2,t1,t2,t3;
    for(int k=1;k<=n;k++)
    {
        if(dis(d,a[k])<=r) continue ;
        if(Cross(p,q,a[k])!=0.0)  //三点不共线。
        {
            c1=(p.x*p.x+p.y*p.y-q.x*q.x-q.y*q.y)/2.0;
            c2=(p.x*p.x+p.y*p.y-a[k].x*a[k].x-a[k].y*a[k].y)/2.0;
            d.x=(c1*(p.y-a[k].y)-c2*(p.y-q.y))/((p.x-q.x)*(p.y-a[k].y)-(p.x-a[k].x)*(p.y-q.y));
            d.y=(c1*(p.x-a[k].x)-c2*(p.x-q.x))/((p.y-q.y)*(p.x-a[k].x)-(p.y-a[k].y)*(p.x-q.x));
            r=dis(d,a[k]);
        }
        else
        {
            t1=dis(p,q); t2=dis(q,a[k]); t3=dis(p,a[k]);
            if(t1>=t2&&t1>=t3)
            { d.x=(p.x+q.x)/2.0; d.y=(p.y+q.y)/2.0; r=dis(p,q)/2.0;}
            else if(t2>=t1&&t2>=t3)
            { d.x=(a[k].x+q.x)/2.0; d.y=(a[k].y+q.y)/2.0; r=dis(a[k],q)/2.0;}
            else
            { d.x=(a[k].x+p.x)/2.0; d.y=(a[k].y+p.y)/2.0; r=dis(a[k],p)/2.0;}
        }
    }
}
void mindis1(ss pi,int n)
{
    d.x=(pi.x+a[1].x)/2;
    d.y=(pi.y+a[1].y)/2;
    r=dis(pi,a[1])/2;
    for(int j=2;j<=n;j++)
      if(dis(d,a[j])>r)
       mindis2(pi,a[j],j-1);
}
void init(double &res)
{
    char ch;
    int flag=0,tmp=0,n,m,num=0;
    while((ch=getchar())<'0'||ch>'9')
       if(ch=='-') flag=1;
    for(m=0,n=0; (ch>='0'&&ch<='9')|| (ch=='.');ch=getchar())
    {
         if(ch=='.') { tmp=1;continue;}
         if(!tmp) m=m*10+ch-'0';
         if(tmp) { n=n*10+ch-'0'; num++;}
    }
    res=m+n*1.0/pow(10,num);
    if(flag) res*=-1;
}
int main()
{
    //freopen("Input.txt","r",stdin);
    int i,n;
    while(scanf("%d",&n),n)
    {
        for(i=1;i<=n;i++)
         scanf("%lf%lf",&a[i].x,&a[i].y);//init(a[i].x);init(a[i].y);输入函数。
      //所有点存在数组a中。
        if(n==1) {printf("0.50\n",a[1].x,a[1].y);continue ;}
        r=dis(a[1],a[2])/2;
        d.x=(a[1].x+a[2].x)/2;
        d.y=(a[1].y+a[2].y)/2;
        for(i=3;i<=n;i++)
         if(dis(d,a[i])>r)
          mindis1(a[i],i-1);
        // printf("%.2lf %.2lf\n",d.x,d.y); //圆心坐标。
        printf("%.2lf\n",r+0.5); //hdu2215 每棵树都是直径为1的,所以最后加上0.5.
    }
    return 0;
}

hdu 3932

hdu 3007

hdu 2215

已做。

空间n个点求最小覆盖球。 看解题报告写的,还没看过模拟退火,看似很高深的东西。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#define MAXN 50
#define eps 1e-7
using namespace std;
struct P
{
	double x,y,z;
}p[MAXN],s;
int n;
double delta,ans;
double dis(P a,P b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
void solve()
{
	s.x=s.y=s.z=0;
	delta=100;
	ans=1e20;
	while(delta>eps)
	{
		int d=0;
		for(int i=0;i<n;i++)
			if(dis(s,p[i])>dis(s,p[d]))
				d=i;
		double md=dis(s,p[d]);
		ans=min(ans,md);
		s.x+=(p[d].x-s.x)/md*delta;
		s.y+=(p[d].y-s.y)/md*delta;
		s.z+=(p[d].z-s.z)/md*delta;
		delta*=0.98;
	}
	printf("%.5f\n",ans);
}
void init(double &res)
{
    char ch;
    int flag=0,tmp=0,n,m,num=0;
    while((ch=getchar())<'0'||ch>'9')
       if(ch=='-') flag=1;
    for(m=0,n=0; (ch>='0'&&ch<='9')|| (ch=='.');ch=getchar())
    {
         if(ch=='.') { tmp=1;continue;}
         if(!tmp) m=m*10+ch-'0';
         if(tmp) { n=n*10+ch-'0'; num++;}
    }
    res=m+n*1.0/pow(10,num);
    if(flag) res*=-1;
}
int main()
{
	//freopen("Input.txt","r",stdin);
	while(scanf("%d",&n), n)
	{
		for(int i=0;i<n;i++)
	    {
	        init(p[i].x);
	        init(p[i].y);
	        init(p[i].z);
	    }
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值