【问题标题】:Divide and conquer algorithm to compute friend points分治算法计算朋友点
【发布时间】:2017-08-12 19:32:28
【问题描述】:

我有一个问题需要通过分而治之来解决。 有一个集合 S,包括 N 个点。 如果有一个平行于轴的正方形,只包含 S 中的两个点 p1 和 p2,那么我们称为 p1 和 p2 朋友点。

现在,我需要使用分治算法来计算 S 中有多少朋友点。

我想了很久。我没有办法。 我需要你的帮助。 我的英语不好,如果你有问题,请问我,我会补充。谢谢。

【问题讨论】:

  • 一个给定的点可以成为多个其他点的朋友吗?想象一组在 p1=(-1, 0)、p2=(0, 0) 和 p3=(+1, 0) 处的三个点。这个套装只有两个朋友点吗?或者会有两对朋友 {p1, p2} 和 {p2, p3} 从而获得三个朋友点?
  • 一个给定的点成为多个其他点的朋友
  • 如果点可以是多个其他点的朋友,最好的算法是构造一个Voronoi Diagram。然后,给定点是位于相邻 Voronoi 区域中的所有其他点的朋友。描述了一种分治算法here。与Voronoi 图密切相关的是Delauney Triangulation。它连接相邻的 Voronoi 点,因此可以看作是“友谊图”。

标签: algorithm


【解决方案1】:

下面的(不一定是最优的)伪代码算法呢?

List<Pair<Point, Point>> findFriends(List<Point> points)
{
    List<Pair<Point, Point>> friends = new List<Pair<Point, Point>>();

    if (points.Count > 1)
    {
        if (points.Count == 2)
        {
           friends.Add(new Pair<Point, Point>(points[0], points[1]);
        }
        else
        {
           int xMedian = getMedianX(points);
           int yMedian = getMedianY(points);
           List<Point> topLeftPoints = selectPoints(points, 0, xMedian-1, yMedian, yMax);
           List<Point> bottomLeftPoints = selectPoints(points, 0, xMedian-1, 0, yMedian-1);
           List<Point> topRightPoints = selectPoints(points, xMedian, xMax, yMedian, yMax);
           List<Point> bottomRightPoints = selectPoints(points, xMedian, xMax, yMedian, yMax);

           friends.Add(findFriends(topLeftPoints));
           friends.Add(findFriends(bottomLeftPoints));
           friends.Add(findFriends(topRightPoints));
           friends.Add(findFriends(bottomRightPoints));      
        }
    }

    return friends;
}

【讨论】:

  • 通过这个实现,你会错过拆分后在不同集合中的所有朋友。想象 (-2, 1) 上的点; (-1, 2); (1, 2); (2, 1); (2, -1); (1, -2); (-1, -2), (-2, -1)。八角形,例如(-1, 2) 和 (-1, -2) 将被忽略...相当棘手。
  • @maraca:是的,这就是我所说的“非最优”的意思。有什么改进建议吗?
【解决方案2】:

诀窍是以这样一种方式进行划分,使各个部分更小并且可以独立处理。我们可以使用类似于快速排序的枢轴将点分成两组。但这比听起来要困难得多,因为如果没有正确完成,集合可能不会在特殊情况下收缩或不独立。

添加朋友:由于无法进一步划分而必须评估的集合的大小是 1(什么都不做)、2(添加对)和 3(将 2 添加到 3对,需要检查)。

寻找支点:计算平均 x 和平均 y 并找到最接近它的点 p

划分:将点划分为 4 个集合 a、b、c 和 d,如下所示。 a,b是a左下,右上分区和c,da左上,右下分区,只保留更好的(取a,b if a.size + b.size p.x || y >= p.y, 设置 c: x = p.y 并设置 d: x >= p.x || y

例子:

* * *    * * *    * * .   * * *
* * * => * p * => * * . , . * * bottom-left top-right partition
* * *    * * *    * * *   . * *

* * .    * * .    * * .   . . .
* * . => * p . => * * . , * * . top-left bottom-right partition
* * *    * * *    * . .   * * *

. . .    . . .    . . .   . . .
* * . => * * . => * . . , . * * bottom-left top-right partition
* * *    * p *    * * *   . * .

等等...简化:

a | b    top-left bottom-right partition: 1st set: a, b, c, p; 2nd set: b, c, d, p.
- p -
c | d    bottom-left top-right partition: 1st set: a, c, d, p; 2nd set: a, b, d, p.

组是独立的,因为 ad 和 cb 中的点不能成为朋友,p 将永远是障碍。左上角右下角分隔点 a 和 d,左下角右上角分隔点 b 和 c。

【讨论】:

  • 对不起。我不明白你的分歧。能举个例子吗?
  • 添加了一个例子
  • 分区b和c会被计算两次。
  • 你会得到两套大约 3/4 的点,所以是的,有些对被检测到了两次,都在上面,但是这些套是独立的,而且它们越来越小。如果您将朋友添加到集合中,则根本没有关系,重复项将被自动丢弃。递归执行 10 次,集合的大小约为总点数的 200 万分之一。
猜你喜欢
  • 2013-10-30
  • 1970-01-01
  • 1970-01-01
  • 2020-01-30
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2021-05-06
  • 2012-10-28
相关资源
最近更新 更多