#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;
}
本文介绍了用于计算平面上最小覆盖圆及三维空间中最小覆盖球的算法实现。通过逐步迭代改进圆心位置来减少覆盖半径,适用于解决特定几何问题。
2752

被折叠的 条评论
为什么被折叠?



