答案 0 :(得分:3)
这些并没有给你提供C ++代码,但它们包括对你需要做的有效算法的深入讨论。
答案 1 :(得分:1)
不确定我是否可以证明它,但在我看来,最佳解决方案的特点是切线(至少)3个点,而所有其他点都在椭圆内(考虑一下!)。因此,如果没有别的,你应该能够通过检查所有~3 ^三个点并检查它们是否定义解决方案来强制它。应该可以通过删除所有必须严格在任何周围椭圆内的点来改进,但我不知道如何做到这一点。也许可以通过x和y坐标对点进行排序,然后做一些奇特的事情。
不是一个完整的解决方案,但这是一个开始。
编辑: 不幸的是,3点不足以定义椭圆。但也许如果你把它限制在切线3点的最小区域的椭圆上?
答案 2 :(得分:0)
(0,0)
我会用approximation search(二进制搜索和线性搜索之间的混合)来标准 genere和test 问题来加速它(但你也可以试试开始,看看它是否有效。
计算解决方案的约束
要限制搜索,您需要找到椭圆的近似放置位置和大小。为此,您可以使用外观圆圈来表示您的观点。很明显,椭圆区域将小于或等于圆形,并且位置将接近。圆圈不一定是最小的圆圈,因此我们可以使用例如:
这将是O(n)
复杂度,其中n
是您的积分数。
搜索"所有"可能的省略号并记住最佳解决方案
所以我们需要找到椭圆中心(x0,y0)
和半轴rx,ry
,而area = M_PI*rx*ry
是最小的。使用近似搜索,每个变量的因子为O(log(m))
,每次迭代需要测试O(n)
的有效性,因此最终的复杂度为O(n.log^4(m))
,其中m
是可能的变量的平均数。每个搜索参数(取决于准确性和搜索约束)。通过简单的粗暴搜索,它将是O(n.m^4)
,这对于m
可能非常大的浮点尤其可怕。
为了加快速度,我们知道椭圆的面积将小于或等于找到圆的面积,因此我们可以忽略所有较大的椭圆。 rx,ry
的约束可以从边界框的纵横比+/-某些保留得出。
这里使用上面链接中的approx
类的简单小 C ++ 示例:
//---------------------------------------------------------------------------
// input points
const int n=15; // number of random points to test
float pnt[n][2];
// debug bounding box
float box_x0,box_y0,box_x1,box_y1;
// debug outscribed circle
float circle_x,circle_y,circle_r;
// solution ellipse
float ellipse_x,ellipse_y,ellipse_rx,ellipse_ry;
//---------------------------------------------------------------------------
void compute(float x0,float y0,float x1,float y1) // cal with bounding box where you want your points will be generated
{
int i;
float x,y;
// generate n random 2D points inside defined area
Randomize();
for (i=0;i<n;i++)
{
pnt[i][0]=x0+(x1-x0)*Random();
pnt[i][1]=y0+(y1-y0)*Random();
}
// compute bounding box
x0=pnt[0][0]; x1=x0;
y0=pnt[0][1]; y1=y0;
for (i=0;i<n;i++)
{
x=pnt[i][0]; if (x0>x) x0=x; if (x1<x) x1=x;
y=pnt[i][1]; if (y0>y) y0=y; if (y1<y) y1=y;
}
box_x0=x0; box_x1=x1;
box_y0=y0; box_y1=y1;
// "outscribed" circle
circle_x=0.5*(x0+x1);
circle_y=0.5*(y0+y1);
circle_r=0.0;
for (i=0;i<n;i++)
{
x=pnt[i][0]-circle_x; x*=x;
y=pnt[i][1]-circle_y; y*=y; x+=y;
if (circle_r<x) circle_r=x;
}
circle_r=sqrt(circle_r);
// smallest area ellipse
int N;
double m,e,step,area;
approx ax,ay,aa,ab;
N=3; // number of recursions each one improves accuracy with factor 10
area=circle_r*circle_r; // solution will not be bigger that this
step=((x1-x0)+(y1-y0))*0.05; // initial position/size step for the search as 1/10 of avg bounding box size
for (ax.init( x0, x1,step,N,&e);!ax.done;ax.step()) // search x0
for (ay.init( y0, y1,step,N,&e);!ay.done;ay.step()) // search y0
for (aa.init(0.5*(x1-x0),2.0*circle_r,step,N,&e);!aa.done;aa.step()) // search rx
for (ab.init(0.5*(y1-y0),2.0*circle_r,step,N,&e);!ab.done;ab.step()) // search ry
{
e=aa.a*ab.a;
// is ellipse outscribed?
if (aa.a>=ab.a)
{
m=aa.a/ab.a; // convert to circle of radius rx
for (i=0;i<n;i++)
{
x=(pnt[i][0]-ax.a); x*=x;
y=(pnt[i][1]-ay.a)*m; y*=y;
// throw away this ellipse if not
if (x+y>aa.a*aa.a) { e=2.0*area; break; }
}
}
else{
m=ab.a/aa.a; // convert to circle of radius ry
for (i=0;i<n;i++)
{
x=(pnt[i][0]-ax.a)*m; x*=x;
y=(pnt[i][1]-ay.a); y*=y;
// throw away this ellipse if not
if (x+y>ab.a*ab.a) { e=2.0*area; break; }
}
}
}
ellipse_x =ax.aa;
ellipse_y =ay.aa;
ellipse_rx=aa.aa;
ellipse_ry=ab.aa;
}
//---------------------------------------------------------------------------
即使这个只有15分的简单例子也需要大约2秒才能计算出来。您可以通过添加启动量(例如仅低于circle_r^2
等的测试区域来提高性能,或者使用某些数学规则更好地选择解决方案区域。如果你使用蛮力而不是近似搜索,期望计算时间可能是几分钟或更长,因此O(scary)
......
请注意,此示例不适用于点的任何宽高比,因为我将rx,ry
的上限硬编码为2.0*circle_r
,这可能还不够。相反,您可以计算点的纵横比的上限和/或条件rx*ry<=circle_r^2
...
还有其他(&#34;更快&#34;)方法,例如可以使用 CCD (循环坐标下降)的变化。但是这些方法通常无法保证找到最佳解决方案或者根本不能找到最佳解决方案......
此处输出示例概述:
点是来自pnt[n]
的单个点,灰色虚线的东西是边界框并且使用外边的圆圈。找到绿色椭圆的解决方案。