给定一个二维平面,其中有n个点。我需要生成一条方程式,将平面分成两部分,使得一侧有n/2个点,另一侧也有n/2个点。
给定一个二维平面,其中有n个点。我需要生成一条方程式,将平面分成两部分,使得一侧有n/2个点,另一侧也有n/2个点。
我假设这些点是不同的,否则可能根本不存在这样的线。
如果这些点是不同的,则总是存在这样一条线,并且可以使用确定性O(nlogn)时间算法找到它。
假设这些点是P1、P2、...、P2n。假设它们不都在同一条直线上。如果是这样的话,我们可以很容易地形成分割线。
首先将这些点转换为所有坐标(x和y)都为正数。
现在假设我们有一个神奇的点Q在y轴上,使得由这些点形成的任何直线(即任何无限直线Pi-Pj)都不经过Q。
既然Q不在这些点的凸包内,我们可以很容易地看出,我们可以通过通过Q的旋转线对这些点进行排序。对于某个旋转角度,一半的点将位于这条旋转线的一侧,另一半将位于另一侧,或者换句话说,如果我们按照线段Pi-Q的斜率对这些点进行排序,我们可以选择第(median)个和第(median+1)个点之间的斜率。这个选择可以通过任何线性时间选择算法在O(n)时间内完成,而不需要实际对这些点进行排序。
现在要选择点Q。
假设Q是(0,b)。
假设Q与P1(x1,y1)和P2(x2,y2)共线。
那么我们有
(y1-b)/x1 = (y2-b)/x2(注意,我们将点平移,使得xi > 0)。
解出b得
b = (x1y2 - y1x2)/(x1-x2)
(如果x1 = x2,则P1和P2不能与Y轴上的点共线)。
考虑|b|。
|b| = |x1y2 - y1x2| / |x1 -x2|
现在让xmax成为最右边点的x坐标,ymax成为最高点的坐标。
还让D成为两个点之间最小的非零x坐标差异(这存在,因为不是所有的xi都相同,也不是所有的点都共线)。
然后我们有|b| ≤ xmax*ymax/D。
因此,选择我们的点Q(0,b),使得| b | > b_0 = xmax * ymax / D
可以在O(nlogn)时间内找到D。
b_0的大小可能会变得非常大,我们可能需要处理精度问题。
当然,更好的选择是随机选择Q!概率为1,您将找到所需的点,从而使期望运行时间为O(n)。
如果我们能够找到一种以O(n)时间选择Q的方法(通过找到其他标准),那么我们可以使该算法在O(n)时间内运行。
在该平面上创建任意一条直线。对于每个点,将其投影到该直线上,即找到距离该点最近的直线上的点。
按照任意方向将这些点沿着该直线排序,并选择直线上的一个点,使得直线两侧的点数相等。
获得垂直于第一条直线并通过该点的直线。该直线的两侧将各有原始点数的一半。
在执行此过程时要避免某些情况。最重要的是,如果所有点都位于单条直线上,则不要选择通过它的垂直线。实际上,选择该直线本身,这样您就不需要担心投影点的问题。在实际的数学计算中,向量投影会非常有用。
这是对将点平面分成两个相等部分的修改,可以处理存在重叠点的情况(此时会说明答案是否存在)。
If number of points is odd, return "impossible".
Pick a random line (two random points)
Project all points onto this line (`O(N)` operation)
(i.e. we pretend this line is our new X'-axis, and write down the
X'-coordinate of each point)
Perform any median-finding algorithm on the X'-coordinates
(`O(N)` or faster-if-desired operation)
(returns 2 medians if no overlapping points)
Return the line perpendicular to original random line that splits the medians
In rare case of overlapping points, repeat a few times (it would take
a pathological case to prevent a solution from existing).
这与其他提出的解决方案不同,时间复杂度为O(N)
。
假设存在一种解决方案,上述方法可能会终止,尽管我没有证明。
尝试以上算法几次,除非你检测到重叠点。如果检测到大量重叠点,则可能会遇到麻烦,但有一种非常低效的暴力解决方案,涉及检查所有可能的角度:
For every "critical slope range", perform the above algorithm
by choosing a line with a slope within the range.
If all critical slope ranges fail, the solution is impossible.
关键角度被定义为可能改变结果的角度(想象一下先前答案的解决方案,将整个点集旋转直到一个或多个点与其他一个或多个点交换位置,越过分割线。这些只有有限多个,我认为它们受到点数的限制,因此如果有重叠点,则暴力方法可能需要 O(N^2)-O(N^2 log(N))
的范围内进行处理。
有些情况显然是无解的。例如,当您有三堆点时。一个点位于位置A,两个点位于位置B,五个点位于位置C。
如果您期望一些合理的分布,您可能可以使用tlayton算法获得良好的结果。为了选择初始线斜率,您可以确定整个点集的范围,并选择最大对角线的角度。
中位数等分一组数字的方式类似于您正在尝试实现的方式,并且可以使用选择算法以O(n)时间计算(Cormen等人的写作更好,因此您可能希望在那里查找)。 因此,找到您的x值Mx(或者如果您愿意,您的y值My)的中位数并将x = Mx(或y = My),该线将轴向对齐并平均分割点。
如果您的问题的性质要求线上不超过一个点(如果您的集合中有奇数个点,则至少有一个点将在该线上),并且您发现已经发生了这种情况(或者您只是想防止此可能性),请将所有点旋转一些随机角度θ,并计算旋转点的中位数。 然后,您将通过-θ旋转计算出的中位线旋转,并将其均匀地分割点。
在有限数量的点中随机选择θ,导致问题再次出现的可能性非常小,但如果出现了,请尝试使用不同的θ再次尝试。
以下是我处理这个问题的方法(假设n是偶数且NO三点共线):
1)选择Y值最小的点。我们称之为点P。
2)以此点为新原点,使所有其他点在此变换后都有正的Y值。
3)对于每个其他点(剩下n-1个点),将其视为极坐标系下的点。每个其他点可以用半径和角度表示。您可以忽略半径,只关注角度。
4)如何找到一条平均分割点的线?找到(n-1)角度的中位数。从点P到具有该中位数角度的点的线将平均分割点。
此算法的时间复杂度为O(n)。
我不知道这有多有用,我见过类似的问题...
如果您已经拥有方向向量(也称为平面维度的系数)。
然后,您可以在该平面内找到两个点,并且仅使用中点公式即可找到该平面的中点。
然后,使用该平面的系数和中点,您可以使用平面的一般方程找到一个与两个点距离相等的平面。
因此,表示另一个变量的表达式将构成线路,以便您可以找到两个平面之间距离相等的线路。
有不同的方法来完成这项任务,例如使用从平面到距离方程的投影,但我认为这会使您的数学变得复杂。
我从Moron和andand那里得到了灵感,并继续形成一个确定性的O(n)算法。
我还假设点是不同的,n是偶数(尽管可以更改算法以支持具有一个点在分界线上的奇数n)。
该算法尝试使用垂直线将点分开。只有当中间的点具有相同的x值时,才会失败。在这种情况下,算法确定左侧和下侧必须有多少个具有相同x值的点,并相应地旋转该线。
我将尝试用一个例子来解释。假设我们在平面上有16个点。首先,我们需要获取第8个最大x值的点和第9个最大x值的点。通过选择算法,这在O(n)内是可能的,正如另一个答案所指出的那样。如果那些点的x值不同,我们就完成了。我们在那两个点之间创建一条垂直线,这样就可以平均分割点。
问题现在是如果x值相等。所以我们有3组点。 左侧的点(x < xa),中间的点(x = xa) 和右侧的点(x > xa)。 现在的想法是计算左侧的点数, 计算出需要多少个点从中间移到那边, 使得一半的点在那一侧。我们可以忽略右侧这里 因为如果左侧有一半的点,那么剩下的一半必然在右侧。我们想要从中间取出y值最低的5个点放在左边, 并将y值最高的点放在右边。 再次使用选择算法,我们得到了第5大和第6大的y值点。 这两个点的x值都等于xa, 否则我们就无法进行下一步, 因为会有一条垂直线。
现在我们可以创建一个点Q,它位于这两个点的中间。 这是结果线上的一个点。 还需要另一个点,以便不分割左侧或右侧的任何点。 为了获得该点,我们需要从左侧获取具有最小角度(bh)的点, 该角度是由该点和Q确定的线与xa处的垂直线之间的夹角。 我们还需要从右侧获取该点(带有角度ag)。 新点R位于具有较小角度的点和垂直线上的点之间 (如果较小角度在左侧,则在Q上方一个点, 如果较小角度在右侧,则在Q下方一个点)。
由 Q 和 R 确定的直线将点分成两部分,使得两侧都有偶数个点。 它不会在左侧或右侧分割任何点, 因为如果这样做,该点将具有更小的角度, 并且将被选择计算 R。
从数学家的角度来看,这应该在 O(n) 的时间内运行良好。 对于计算机程序而言,很容易找到精度成为问题的情况。 一个包含 4 个点的示例是 A(0, 100000000),B(0, 100000001),C(0, 0),D(0.0000001, 0)。 在此示例中,Q 将是 (0, 100000000.5),R 将是 (0.00000005, 0)。 这将在左侧得到 B 和 C,在右侧得到 A 和 D。 但是,由于舍入误差的原因,A 和 B 可能都在分界线上, 或者只有其中一个。 因此,这取决于输入值是否适合此算法的要求。
> O(n)
> O(1)
> O(n)
> O(n)
> O(n)
> O(n)
> O(n)
> O(n)
> O(1)
> O(n)
> O(n)
> O(n)
> O(1)
> O(1)
补充M的答案:一种在O(n log n)时间内生成一个Q(不远)的方法。
首先,让Q成为y轴上的任何点,即Q = (0,b)
- 一些好的选择可能是(0,0)或(0,(ymax-ymin)/2)。
现在检查是否有两个点(x1, y1),(x2, y2)与Q共线。任何点和Q之间的线是y = mx + b
;由于b是常数,这意味着如果它们的斜率m
相等,则两个点与Q共线。因此确定所有点的斜率mi并检查是否有任何重复:(使用哈希表进行平摊的O(n)
)
如果所有的m不同,我们就完成了;我们找到了Q,而上面的M算法生成了O(n)
步的线。
如果两个点与Q共线,我们将把Q向上移动一个微小的量ε,Qnew = (0, b + ε),并且证明Qnew将不会与另外两个点共线。
下面是推导出的ε的标准:
ε < mminΔ*xmin
首先,我们的m看起来像这样:
mi = yi/xi - b/xi
让我们找到任意两个不同的mi之间的最小差异,并将其称为mminΔ (例如,通过对所有i排序,然后比较mi和i+1之间的差异)
如果我们将b增加ε,那么m的新方程变为:
mi,new = yi/xi - b/xi - ε/xi = mi,old - ε/xi
由于ε>0且xi>0,所有的m都会减少,而且最多减少ε/xmin。因此,如果
如果ε/xmin < mminΔ,即 ε < mminΔ*xmin 则两个先前不相等的mi将保证保持不相等。现在只需要证明如果 m1,old = m2,old,那么 m1,new =/= m2,new。由于两个 mi 都减少了 ε/xi 的数量,这等价于证明 x1 =/= x2。如果它们相等,则:
y1 = m1,oldx1 + b = m2,oldx2 + b = y2
这与我们假设的所有点都不同矛盾。因此,m1,new =/= m2,new,且没有两个点与 Q 共线。