【问题标题】:How to make shortest path between two points algorithm faster?如何使两点算法之间的最短路径更快?
【发布时间】:2016-03-11 06:46:35
【问题描述】:

我写了这个算法。它可以工作(至少在我的简短测试用例中),但在较大的输入上花费的时间太长。我怎样才能让它更快?

// Returns an array of length 2 with the two closest points to each other from the
// original array of points "arr"
private static Point2D[] getClosestPair(Point2D[] arr) 
{

    int n = arr.length;

    float min = 1.0f;
    float dist = 0.0f;
    Point2D[] ret = new Point2D[2];

    // If array only has 2 points, return array
    if (n == 2) return arr;

    // Algorithm says to brute force at 3 or lower array items
    if (n <= 3)
    {
        for (int i = 0; i < arr.length; i++)
        {
            for (int j = 0; j < arr.length; j++)
            {                   
                // If points are identical but the point is not looking 
                // at itself, return because shortest distance is 0 then 
                if (i != j && arr[i].equals(arr[j]))
                {
                    ret[0] = arr[i];
                    ret[1] = arr[j];
                    return ret;                   
                }
                // If points are not the same and current min is larger than
                // current stored distance
                else if (i != j && dist < min)
                {
                    dist = distanceSq(arr[i], arr[j]);
                    ret[0] = arr[i];
                    ret[1] = arr[j];
                    min = dist;
                }        
            }
        }

        return ret;
    }

    int halfN = n/2;

    // Left hand side
    Point2D[] LHS = Arrays.copyOfRange(arr, 0, halfN);
    // Right hand side
    Point2D[] RHS = Arrays.copyOfRange(arr, halfN, n);

    // Result of left recursion
    Point2D[] LRes = getClosestPair(LHS);
    // Result of right recursion
    Point2D[] RRes = getClosestPair(RHS);

    float LDist = distanceSq(LRes[0], LRes[1]);
    float RDist = distanceSq(RRes[0], RRes[1]);

    // Calculate minimum of both recursive results
    if (LDist > RDist)
    {
        min = RDist;
        ret[0] = RRes[0];
        ret[1] = RRes[1];
    }
    else
    {
        min = LDist;
        ret[0] = LRes[0];
        ret[1] = LRes[1];       
    }


    for (Point2D q : LHS)
    {
        // If q is close to the median line
        if ((halfN - q.getX()) < min)
        {
            for (Point2D p : RHS)
            {
                // If p is close to q
                if ((p.getX() - q.getX()) < min)
                {               
                    dist = distanceSq(q, p);        
                    if (!q.equals(p) && dist < min)
                    {
                        min = dist;
                        ret[0] = q;
                        ret[1] = p;
                    }

                }

            }
        }
    }

    return ret;
}

private static float distanceSq(Point2D p1, Point2D p2)
{
    return (float)Math.pow((p1.getX() - p2.getX()) + (p1.getY() - p2.getY()), 2);
}

我大致遵循此处解释的算法:http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html

这里还有一个带有伪代码的不同资源:

http://i.imgur.com/XYDTfBl.png

我无法更改函数的返回类型,或添加任何新参数。

感谢您的帮助!

【问题讨论】:

    标签: java algorithm shortest-path


    【解决方案1】:

    您可以做几件事。

    首先,您可以通过将第二次迭代更改为仅在“提醒”点上运行来非常简单地缩短程序运行时间。这有助于避免为每个值同时计算 (i,j)(j,i)。为此,只需更改:

    for (int j = 0; j < arr.length; j++)
    

    for (int j = i+1; j < arr.length; j++)
    

    这仍然是O(n^2)

    您可以通过迭代点来实现O(nlogn) 时间,并将每个点存储在智能数据结构中(kd-tree 最有可能)。在每次插入之前,找到已经存储在 DS 中的最近点(kd-tree 在O(logn) 时间支持这一点),它是您的最小距离候选。

    【讨论】:

    • 我的 TA 说应该减少执行次数的基本操作是以下行:if ((p.getX() - q.getX()) &lt; min) 我已经在min = 0 时添加了提前退出并实施了您的建议,但是它最多只能减少几毫秒。还有什么想法吗?
    • 几毫秒是什么?目前需要什么时间,你想得到什么。就像我说的,要获得真正的渐近改进 - 你应该使用 k-d 树。
    • 有 2 秒的上限。显然它应该能够在那个时间内通过 100 000 的测试用例。
    【解决方案2】:

    我相信链接算法提到了按一个坐标对数组进行排序,以便给定点 1 到 2000 中的 LHS q,如果点 200 处的 RHS p 仅距离其 x 距离超过“min”距离,则可以避免检查剩下的201到2000分。

    【讨论】:

      【解决方案3】:

      我想通了 - 大大缩短了时间。 distanceSq 函数错误。最好改用 Java 的 Point2D somepoint.distanceSq(otherpoint); 方法。

      至于n 为 3 时的原始蛮力(在那种情况下它只会是 3 或 2),线性搜索更好更有效。

      在蛮力条件之后,内部for 循环中对min 变量的检查也是错误的。使用平方距离很好,但 min 不是平方的。它保留了原始距离,这意味着 min 在两次检查中都必须是平方根(一次在外循环中,一次在内部循环中)。

      所以,

      if ((p.getX() - q.getX()) < min)
      

      应该是

      if ((p.getX() - q.getX()) < Math.sqrt(min))
      

      其他检查也是如此。

      感谢大家的回答!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-17
        • 1970-01-01
        • 2016-03-26
        • 2010-12-03
        • 2017-02-03
        • 2016-03-04
        相关资源
        最近更新 更多