找一个点使得到跟顶点最大距离最小。
相当于找一个覆盖所有点的圆。
最小圆覆盖用随机增量(O(n^3)概率均摊到O(n))。
最小球覆盖用退火/三分三分再三分
圆 C;
for(i=1 to n)
{
if(P[i] 不在 C 内)
{
C = {P[i], 0};
for(j=1 to i-1)
{
if(P[j] 不在 C 内)
{
C = {0.5*(P[i]+P[j]), 0.5*dist(P[i], P[j])};
for(k=1 to j-1)
{
if(P[k] 不在 C 内)
{
C = 外接圆(P[i], P[j], P[k]);
}
}
}
}
}
}
#include
#include
#include
using namespace std;
typedef double DB;
const int N=100005;
struct node
{
DB x,y;
}a[N],O;
int n;
DB r;
inline DB power(DB x)
{
return x*x;
}
inline DB dis(node a,node b)
{
return sqrt(power(a.x-b.x)+power(a.y-b.y));
}
inline bool in_circle(node a)
{
return dis(a,O)<=r?1:0;
}
inline int calc(DB a,DB b,DB c,DB d,DB e,DB f)
{
O.x=(b*f-d*e)/(b*c-a*d);
O.y=(c*e-a*f)/(b*c-a*d);
}
inline void min_cover_circle(void)
{
register int i,j,k;
random_shuffle(a+1,a+n+1);
for (i=1;i<=n;++i)
if (!in_circle(a[i]))
{
O=a[i]; r=0;
for (j=1;j<i;++j)
if (!in_circle(a[j]))
{
O.x=(a[i].x+a[j].x)/2.0; O.y=(a[i].y+a[j].y)/2.0; r=dis(a[i],O);
for (k=1;k<j;++k)
if (!in_circle(a[k])) calc(a[i].x-a[j].x,a[i].y-a[j].y,a[i].x-a[k].x,a[i].y-a[k].y,
((power(a[i].x)-power(a[j].x))-(power(a[j].y)-power(a[i].y)))/2.0,
((power(a[i].x)-power(a[k].x))-(power(a[k].y)-power(a[i].y)))/2.0),r=dis(a[i],O);
}
}
printf("%.10lf %.10lf %.10lf",O.x,O.y,r*r/2.);
}
int main()
{
register int i; scanf("%d",&n);
for (i=1;i<=n;++i)
scanf("%lf%lf",&a[i].x,&a[i].y);
min_cover_circle();
return 0;
}
(还不懂,正确性不保证)
//******************THE PROGRAM BEGINING******************
struct node
{
double x, y;
}p[maxn], now;
double dis(node a, node b)
{
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}
double solve(int n)
{
double ans, cmp;
double T = 100.0;
double delat = 0.98;
now.x = now.y = 0.0;
int pos = 0;
while (T > eps)
{
pos = 0;
ans = dis(now, p[pos]);
per(i, 0, n - 1)
{
cmp = dis(now, p[i]);
if (cmp > ans)
{
pos = i;
ans = cmp;
}
}
now.x += (p[pos].x - now.x) / ans * T;
now.y += (p[pos].y - now.y) / ans * T;
T *= delat;
}
return ans;
}
int main()
{
int n;
scanf("%d", &n);
per(i, 0, n - 1)
scanf("%lf %lf", &p[i].x, &p[i].y);
double ans = solve(n);
printf("%.20lf %.20lf %.20lf\n", now.x, now.y, ans*ans / 2.);
cin >> n;
return 0;
}
常数较大且和精度有关,
#include
#include
#include
#include
using namespace std;
const int maxn = 100005;
const double eps = 1e-7;
double minx, miny, maxx, maxy;
struct Point
{
double x, y;
Point() {}
Point(double _x, double _y)
{
x = _x;
y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x, y - b.y);
}
double operator *(const Point &b)const
{
return x * b.x + y * b.y;
}
};
Point p[maxn];
int T;
double dist(Point a, Point b)
{
Point x = a - b;
return sqrt(x * x);
}
double f(double x, double y)
{
Point ans1 = Point(x, y);
double sum = -1.0;
for (int i = 0; i<T; i++)
{
sum = max(dist(ans1, p[i]), sum);
}
return sum;
}
double three_search2(double x)
{
double l = miny, r = maxy;
while (r - l>eps)
{
double lmid = l + (r - l) / 3;
double rmid = r - (r - l) / 3;
if (f(x, lmid) >= f(x, rmid))
{
l = lmid;
}
else
{
r = rmid;
}
}
return l;
}
Point three_search()
{
double l = minx, r= maxx;
while (r - l>eps)
{
double lmid = l + (r - l) / 3;
double rmid = r - (r - l) / 3;
if (f(lmid, three_search2(lmid)) >= f(rmid, three_search2(rmid)))
{
l = lmid;
}
else
{
r = rmid;
}
}
return Point(l, three_search2(l));
}
int main()
{
scanf("%d", &T);
minx = 10001.0,maxx= -1.0;
miny = 10001.0, maxy = -1.0;
for (int i = 0; i<T; i++)
{
scanf("%lf %lf", &p[i].x, &p[i].y);
minx = min(minx, p[i].x), maxx = max(maxx, p[i].x);
miny = min(miny, p[i].y), maxy = max(maxy, p[i].y);
}
Point ans = three_search();
printf("%.20lf %.20lf %.20lf\n", ans.x, ans.y, f(ans.x, ans.y)*f(ans.x, ans.y)/2.);
return 0;
}
只能退火三分。
否则太难了。