拆分点集,算法

时间:2013-01-08 23:00:57

标签: algorithm

我正在学习测试,我无法解决这个问题:

  

我们得到一组 n< 1000 点和整数 d 。任务是创建两个不相交的点 A_1 A_2 (该联合被赋予 n 点的集合)以使得距离来自 A_i (对于i = 1或2)的每对点之间的(欧几里德)小于或等于 d 。如果无法打印,请打印 -1

     

例如,输入:

     

d = 3,并指出:

     

(5,3),(1,1),(4,2),(1,3),(5,2),(2,3),(5,1)

     

我们可以创建:

     

A_1 = {(2,3),(1,3),(1,1)}

     

A_2 = {(5,3),(4,2),(5,2),(5,1)}

     

因为来自A_i的每对点(对于i = 1或2)足够接近。

我真的想知道如何解决它,但不知道。由于n很小,算法甚至可以是O(n ^ 2 log n),但我不知道如何启动。我在想,也许从计算每对点之间的距离开始,然后取两个最大距离的点并将它们放入不同的组(如果它们的距离大于d)。然后对剩下的对重复此步骤,但问题是如何决定合法地放置下一个点的位置。任何人都可以帮助这个算法吗?

3 个答案:

答案 0 :(得分:5)

让我们考虑一个带有 n 节点的简单图表(对应于 n 点)。如果两个对应点之间的距离大于 d ,则连接两个节点。

如果可以创建两个脱离集,我们必须有一个双向图(如果某些节点没有连接到其他节点,它们可以放在任何集中)。

因此,我们只需要测试图的二分性,这很简单:

http://en.wikipedia.org/wiki/Bipartite_graph#Testing_bipartiteness

答案 1 :(得分:1)

从距离矩阵开始似乎是一个好主意。然后在这个距离矩阵中挑选每个大于d的条目。此条目意味着相应的点必须在不同的集合中。

从两个空集开始并迭代所有相关条目(> d)。

如果集合为空,请将两个点放入其中。否则有三种选择:

  1. 如果清楚哪个点属于哪个,则将它们放入其中(这意味着,插入该点会保留最大距离标准,可以从距离矩阵中获得)。
  2. 如果无法将点插入其中一个集合中,则问题无法解决。
  3. 如果这两个点都有可能,我们就有问题了。我建议开始一对新的点集并将点数放入其中。然后,如果后续点对再次不清楚,请检查第二组对。如果还不清楚,请检查第三组对,依此类推。如果将点对插入到上一组中,请检查以下几组,如果现在清除了点。最后,你有一组成对的点数,可以按照你的意愿联合起来。

  4. 我对第二种方法有了一个想法,它类似,但应该更快一点。

    我们也从距离矩阵开始。

    除了这两组之外,我们还维护一个堆栈,队列或任何新添加的条目。

    因此,如果我们从距离矩阵中选择第一个相关条目,则将这些点添加到两个队列中。只要其中一个队列中有条目,请执行以下操作:

    从队列中删除该点并将其插入到集合中。如果插入打破了最大距离标准,则问题无法解决。检查此点的距离矩阵中的行或列,并提取此行/列中的每个相关条目。将伙伴点添加到另一组的队列中(因为它必须位于不同的集合中)。

    如果两个队列都为空,请将尚未访问过的下一个相关条目添加到队列中并重新开始。

    该算法的优点是按照它们可以相互影响的顺序处理这些点。因此,不需要一对以上的套装。

答案 2 :(得分:1)

想想一个阵列,顶部的所有点和侧面的所有点。

如果定义单元格的两个点(左侧和顶部)大于d,则填充任何单元格中的零,如果两个点小于d,则填充一个。

       (5,3), (1,1), (4,2), (1,3), (5,2), (2,3), (5,1)
(5,3),          0      1      0      1      1      1
(1,1),   0             0      1      0      1      0
(4,2),   1      0             0      1      1      1
(1,3),   0      1      0             0      1      0
(5,2),   1      0      1      0             0      1
(2,3),   1      1      1      1      0             0
(5,1)    1      0      1      0      1      0

(注意:您必须填写每个三角形,并翻转相同的0和1。)

忽略对角线。注意右上角的三角形部分。

跳过第0列。

从第1列开始,如果顶行没有1,则将其与右行的另一列交换,其中第一列的列为1。然后交换相同的行以保持对角线空白。 (如果没有,则没有解决方案。)[示例:交换第2列和第3列以及第2行和第3行]请注意,此行的选择可能会成为优化因素。

移动到下一列,如果它在顶行中没有1,则用右边的列交换并交换相应的行。如果没有,请尝试在其下方的行中交换该行,并在该列中包含1并执行相应的列。如果低于对角线,则应忽略它下面的行。

我们正在收集三角形左上角中有1个点的点。这些点都可以放在其中一个集合中。

这是我迷失在脑海中的地方,但你必须从三角形的右下角开始做一个类似的过程,并收集将在另一个集合中的点。交换行和相应的列以收集三角形右下角的1。

一旦你交换了足够的行,你可以在右上角形成一个矩形 - 一个没有左下角的真正矩形 - 这个矩形包含所有的0,你有一个解决方案。如果你不能这样做,那就没有办法解决。

最低行与三角形中的1和最右边的列进行比较,三角形中的1和它们相遇的单元格。该单元格必须位于三角形中才能找到解决方案。

(我给你留下了一个很大的“待办事项”,找到如何交错行和列的交换,以清除三角形的左上角和右下角的0。也许这里的讨论可以解决如何使它工作。或者发现它不起作用。)