假设我们有两个矩形A,B和一个圆R.我们想确定是否对于任何三个点r,a,b这样“r中的r \ n,A中的a \,B中的b \”, “dist(r,a)< dist(r,b)”将永远保持? dist()返回两点之间的欧几里德距离。换句话说,我们想测试A是否比R更接近于R。
请注意,矩形和圆形在高维空间中可能是超矩形和超球形,矩形是轴平行的。
是否存在在多项式时间内运行的测试算法(关于维D的数量)? O(D)可能吗?
PS:测试应该是完整的,即没有误报或真阴性。
答案 0 :(得分:0)
首先,您可以考虑圈子的中心。如果中心更接近一个矩形,则圆圈更近。接下来,将您的中心点与定义矩形的平面进行比较,以将其分割成几个可能的体积之一(基本上,矩形的多少平面位于正确的一侧)。对于剩余的平面(它不位于正确的一侧),找到从点到平面的每条轴的距离,并将其视为距离向量。它的标准是从圆心到矩形的欧氏距离。这个解决方案应该是O(d),并且非常好用,因为你的矩形是轴对齐的。
答案 1 :(得分:0)
首先,由于我们在N维空间中工作,让我们称这些对象为NBox
和NBall
。这些定义了N维体积。
假设框的轴与欧几里德空间的规范单位向量对齐,则NBox
可以表示为两个N维双数组Min
和Max
沿坐标轴,或作为坐标轴上Range<double>
投影的单个N维列表。 NBall
可以表示为单个N维双数组Center
和双Radius
。一个NPoint
,一个N维点,如此(在c#中):
public interface INDimensional
{
int Dimension { get; }
}
public class NPoint : INDimensional
{
readonly double[] point;
public NPoint(double[] point)
{
if (point == null)
throw new ArgumentNullException();
if (point.Length < 1)
throw new ArgumentException();
this.point = point.ToArray(); // copy
}
public int Dimension { get { return point.Length; } }
public double this[int i] { get { return point[i]; } }
public IList<double> Coordinates { get { return Array.AsReadOnly(point); } }
}
public class NBall : INDimensional
{
readonly NPoint center;
readonly double radius;
public NBall(double[] center, double radius)
{
if (Math.Abs(radius) < Accuracy.AbsoluteDoubleTolerance)
this.radius = 0;
else if (radius < 0)
throw new ArgumentException();
else
this.radius = radius;
this.center = new NPoint(center);
this.radius = radius;
}
public int Dimension { get { return center.Dimension; } }
public double this[int i] { get { return center[i]; } }
public NPoint Center { get { return center; } }
public double Radius { get { return radius; } }
}
public class NBox : INDimensional
{
readonly double[] min;
readonly double[] max;
static void ComputeExtremes(double[] point1, double[] point2, out double[] min, out double[] max)
{
if (point1 == null || point2 == null)
throw new NullReferenceException();
if (point1.Length != point2.Length)
throw new ArgumentException();
min = new double[point1.Length];
max = new double[point1.Length];
for (int i = 0; i < point1.Length; i++)
{
// Handle double-precision rounding issues where point1[i] and point2[i] so nearly equal that they somehow got inverted.
min[i] = Math.Min(point1[i], point2[i]);
max[i] = Math.Max(point1[i], point2[i]);
}
}
public NBox(double[] min, double[] max)
{
ComputeExtremes(min, max, out this.min, out this.max);
}
public int Dimension { get { return min.Length; } }
public Range<double> this[int i] { get { return new Range<double>(min[i], max[i]); } }
public IList<double> Min { get { return Array.AsReadOnly(min); } }
public IList<double> Max { get { return Array.AsReadOnly(max); } }
}
首先,给定一个NPoint,NBox上最近的点是什么?它可以通过坐标协调完成。要获得最近点的第i个坐标值,请查看它是否落在框的第i个范围内。如果在内部,坐标值是该点的坐标值。如果更小,则坐标值是范围最小值。如果更大,则为最大范围。
public static class NDimensionalExtensions
{
public static bool FindClosest(this Range<double> range, double other, out double closestParameter)
{
if (other <= range.Min)
{
closestParameter = range.Min;
return false;
}
if (other >= range.Max)
{
closestParameter = range.Max;
return false;
}
closestParameter = other;
return true;
}
}
public class NBox
{
public bool FindClosest(NPoint other, out NPoint closestPoint)
{
if (other.Dimension != Dimension)
throw new ArgumentException();
double[] closest = new double[other.Dimension];
bool allInside = true;
for (int i = 0; i < Dimension; i++)
{
allInside = allInside && this[i].FindClosest(other[i], out closest[i]);
}
closestPoint = new NPoint(closest);
return allInside;
}
}
其次,给定一个NBox
,与另一个NBox最近的点是什么?嗯,这不是唯一定义的,因为如果框沿着轴在某个范围内重叠,则可以选择范围重叠内的任何坐标值。但是,由于我们只对最终计算距离感兴趣,这没关系,我们可以选择重叠的中心:
public static class NDimensionalExtensions
{
public static bool FindClosest(this Range<double> range, Range<double> other, out double closestParameter)
{
if (other.Max <= range.Min)
{
closestParameter =range.Min;
return false;
}
else if (other.Min >= range.Max)
{
closestParameter = range.Max;
return false;
}
// return in the middle of the overlap
closestParameter = 0.5 * Math.Max(range.Min, other.Min) + 0.5 * Math.Min(range.Max, other.Max);
return true;
}
}
public class NBox
{
public bool FindClosest(NBox other, out NPoint closestPoint)
{
if (other.Dimension != Dimension)
throw new ArgumentException();
double[] closest = new double[other.Dimension];
bool allInside = true;
for (int i = 0; i < Dimension; i++)
{
allInside = allInside && this[i].FindClosest(other[i], out closest[i]);
}
closestPoint = new NPoint(closest);
return allInside;
}
}
现在我们知道如何计算盒子和点之间的最近点,很容易获得盒子,点和球之间的距离。两个点和/或框之间的距离是最近点之间的距离,如果它们相交则为零。 NBall
与框或点之间的距离是最近点之间的距离,小于半径,或者如果差异为负(交叉点)则为零。
public interface INDimensional
{
double GetDistance(NBox other);
}
public class NPoint : INDimensional
{
public double GetDistance(NPoint other)
{
if (Dimension != other.Dimension)
throw new ArgumentException();
double distSq = 0;
for (int i = 0; i < Dimension; i++)
{
var dot = (this[i] - other[i]);
distSq += dot * dot;
}
return Math.Sqrt(distSq);
}
public double GetDistance(NBox other)
{
NPoint closestPoint;
if (other.FindClosest(this, out closestPoint))
return 0;
return GetDistance(closestPoint);
}
}
public class NBall : INDimensional
{
public double GetDistance(NBox other)
{
NPoint closestPoint;
var allInside = other.FindClosest(Center, out closestPoint);
if (allInside)
return 0;
double distance = closestPoint.GetDistance(Center) - Radius;
if (distance < 0)
distance = 0;
return distance;
}
}
public class NBox : INDimensional
{
public bool FindClosest(NBox other, out NPoint closestPoint)
{
if (other.Dimension != Dimension)
throw new ArgumentException();
double[] closest = new double[other.Dimension];
bool allInside = true;
for (int i = 0; i < Dimension; i++)
{
allInside = allInside && this[i].FindClosest(other[i], out closest[i]);
}
closestPoint = new NPoint(closest);
return allInside;
}
public double GetDistance(NBox other)
{
NPoint myClosest, boxClosest;
if (FindClosest(other, out myClosest))
return 0;
if (other.FindClosest(this, out boxClosest))
return 0;
return myClosest.GetDistance(boxClosest);
}
}
根据GetDistance(NBox other)
上的INDimensional
方法,您现在可以找出INDimensional
个对象集合中哪个最接近给定NBox
。
这可以通过使用距离平方BTW进行优化。
所以,所有这些看起来都是O(N)。
但是,如果框沿着轴而不是规范坐标轴轴对齐怎么办?在这种情况下,有必要将所有点转换为轴空间,或者采用带有轴的点积来产生正确的间隔。并且这个将是O(N平方),因为将N维点转换为另一个坐标系需要N平方乘法。
我没有定义Range<double>
课程,你可以自己做。我还没有真正测试过上面的代码,因为你对算法感兴趣而不是实现。最后,这是Accuracy
类的存根:
public static class Accuracy
{
public static double AbsoluteDoubleTolerance
{
get
{
return 100 * double.Epsilon;
}
}
}
答案 2 :(得分:0)
我可以想到一个涉及矩形(或超立方体)的所有面和顶点的算法。因此,不幸的是,维度的数量呈指数关系。但至少它应该是正确的。
给定一个点P.给定矩形内的最近点是P本身或重新旋转边界/表面上的另一个点。
给定一个点P.给定矩形内的最远点是顶点(角)之一。
因此,如果我们想检查矩形A是否比矩形B更接近圆R,那么我们搜索一个计数器示例。如果我们找不到,A更接近。
假设存在这样的反例(r,a,b)。然后我们可以将点移动得更远,甚至更近,并获得一个更“强大”的反例。 我们只检查这些“最强”的潜在反例。 因此,如果R中有一个点r,其中A中的最远点不比B中的最近点更接近,则A不会更接近R.但是如果我们找不到这样的点r,则A更接近于R,根据jojer的条件。
如引理1所述,我们只检查B的每个表面(2d的边缘)上的b点。 根据引理2,我们只检查A顶点的a点。
如果我们现在检查所有这些点对所有这些b点,将空格分成两半,并显示圆圈完全处于更靠近a的一半,那么就没有反例。
空间划分是2个超平面和超抛物线的复合(如果我们检查A的顶点与B的表面)参见示例:http://imgur.com/hf2cJ0c
因此,我们构造所有这些分割平面/抛物面并测试圆心的方向距离是否大于其半径。 如果是这样,则可能没有三重(r,a,b)作为反例。
整个过程应该只是对一些二次形式的评估,并且由顶点 - 顶点 - 对和顶点 - 表面 - 对的数量决定,它们在维度的数量上呈指数。