我在二维平面上有一组点(xy)说n点。
(x1, y1), (x2, y2), (x3, y3), ......................., (xn, yn)
我的目标是绘制图表。 iff中将连接图中的两个节点(点)
abs(difference in x coordinate) + abs(difference in y coordinate) = L(given)
。
可以O(n*n)
完成。是否有可能有效地做到这一点。
BTW我正在尝试解决this问题
答案 0 :(得分:2)
您可以在O( n log n + E )时间内执行此操作,其中 E 是你最终得到的实际边数(即邻居对的数量)。
对于任何给定点,其允许的邻居位置形成菱形,边长 L √2:
*
* *
* *
* *
* o *
* *
* *
* *
*
如果按 x + y 对点进行排序,并回退到 x - y ,那么单个O( n + E )通过排序点将允许您找到此类型的所有邻居:
*
*
*
*
o *
每个点。 (为此,您使用索引i
来跟踪您正在寻找邻居的当前点,并使用单独的索引j
来跟踪允许的邻居行,以便 X <子>Ĵ子> - ý <子>Ĵ子> = X <子> I 子> - < em> y i + L 。这听起来像是O( n 2 ),因为你有两个索引进入数组;但诀窍是j
随着i
单调递增,所以i
和j
中的每一个只生成一个单< / em>传递数组。这甚至可以是O( n )传递,除非你找到( x i sub>, y i ),那么你需要将它们重新视为( x i + 1}的潜在邻居, y i + 1 ),所以你不能增加j
。所以它出现在O( n < / em> + E )传递。)
然后您可以通过 y - x 重新排序它们,并回退到 x + y ,并且重复这个过程找到这些邻居:
*
*
*
*
* o
由于邻居是一种对称关系,你实际上并不需要担心剩下的邻居:
o
* *
* *
* *
*
(整体O( n 日志 n + E )时间包括O( n log n )对点进行排序的时间加上两个O( n + E )传递的时间。)
答案 1 :(得分:1)
鉴于对数据的某些假设,当然可以有效地做到这一点。我会考虑更一般的情况。例如,如果点均匀分布且相互作用距离L(given)
相对于数据的扩展较小,则可以通过对粒子进行分级将问题转换为O(n)
。
这会将你从左边的情况带到右边的情况:
bin的大小为>=L(given)
,对于任何粒子,都会搜索粒子的bin和8个相邻的bin。如果bin中的粒子数平均为d
,则问题可在O(9dn)=O(n)
时间内解决。
答案 2 :(得分:0)
与上述相关的另一种可能性是使用稀疏矩阵结构将1
值存储在所有点的位置,并在其他地方存储0
值。
虽然存在很好的库,但你可以通过提出一个结合了x
和y
坐标的哈希来伪造它。在C ++中看起来像:
std::unordered_set< std::pair<int,int> > hashset;
预先设定散列表,这样可能比避免昂贵的重新散列所需的量大30-50%。
将所有点添加到hashset;这需要O(n)
时间。
现在,交互距离L(given)
定义了一个围绕中心点的菱形。您可以预生成此钻石的偏移列表。例如,如果L=2
,则偏移量为:
int dx[]={0,-2,-1,0,1,2, 1,0,-1};
int dy[]={0, 0, 1,2,1,0,-1,2,-1};
现在,对于每个点,循环偏移列表并将它们添加到该点的坐标。这会生成一个隐含的邻居可能位置列表。使用hashset检查该邻居是否存在。这需要O(n)
时间,并且如果8L << N
(有一些关于可从第一个节点到达的邻居数量的资格),则效率很高。
答案 3 :(得分:0)
我非常喜欢ruakh @的解决方案。另一种方法是允许逐渐增加点集而不损失效率。
要添加每个点P,您需要在树中搜索符合条件的点Q,并在找到任何点时添加边。
在任何k-d树搜索的每个级别,都有可用的每个孩子代表的矩形范围。在这种情况下,只有当它的范围可能包含匹配PIe的点时,您才会继续搜索“向下”进入子节点,该矩形必须包含ruakh @描述的钻石的某些部分。
分析k-d树搜索通常很棘手。我很确定这个算法在一个随机点集的预期O(| E | log n)时间内运行,但是很容易想象性能更好的点集和其他更差的点集。
答案 4 :(得分:-1)
考虑行y = x
和y = -x
考虑每个点与这些线的距离。
只有当它们与这两条线的距离正确时才连接两个点。
因此,您可以按距离将所有点存储到这些线上。然后在每个桶中,有一个有序的点映射(按它们沿着它们的距离排序)。此有序地图中正确距离内的任何点都应在图表中连接。
应该是N * Log(N)更糟的情况,即使所有的点都在彼此的顶部。