Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make shortest path between two points algorithm faster?

I wrote this algorithm. It works (at least with my short test cases), but takes too long on larger inputs. How can I make it faster?

// 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);
}

I am loosely following the algorithm explained here: http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html

and a different resource with pseudocode here:

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

I cannot change the return type of the function, or add any new arguments.

Thanks for any help!

like image 646
Dan Avatar asked Mar 11 '16 06:03

Dan


People also ask

What is shortest path algorithm?

Shortest Path Algorithms. The shortest path problem is about finding a path between $$2$$ vertices in a graph such that the total sum of the edges weights is minimum.

What is the shortest path from 1 to 2 in graph?

The task is to find the shortest path from the source vertex to all other vertices in the given graph. Explanation: For the given input, the shortest path from 1 to 1 is 0, 1 to 2 is 1 and so on. Recommended: Please try your approach on {IDE} first, before moving on to the solution.

How to print the shortest path from 1 to 3?

Given a graph and two nodes u and v, the task is to print the shortest path between u and v using the Floyd Warshall algorithm. Shortest path from 1 to 3 is through vertex 2 with total cost 3.

How do I find the shortest path between two nodes?

Recommended: Please try your approach on {IDE} first, before moving on to the solution. The main idea here is to use a matrix (2D array) that will keep track of the next node to point if the shortest path changes for any pair of nodes. Initially, the shortest path between any two nodes u and v is v (that is the direct edge from u -> v).


1 Answers

There are several things you can do.

First, you can very simply cut the time the program takes to run by changing the second iteration to run only on the "reminder" points. This helps you to avoid calculating both (i,j) and (j,i) for each values. To do so, simply change:

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

to

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

This will still be O(n^2) though.

You can achieve O(nlogn) time by iterating the points, and storing each in a smart data structure (kd-tree most likely). Before each insertion, find the closest point already stored in the DS (the kd-tree supports this in O(logn) time), and it is your candidate for minimal distance.

like image 200
amit Avatar answered Nov 05 '22 12:11

amit