Home > Software design >  Shortest path algorithm in graph for queries
Shortest path algorithm in graph for queries

Time:12-18

I have a weighted undirected Graph. Its vertices are part of two sets - S and T. Firstly, the edges are entered. Then it's specified which vertices are part of the T set (the rest are part of the S set). Then q queries follow. For every query(consists of a source vertex), the program must print the shortest path between the specified source vertex and any vertex of the set T.
I implemented the program using Dijkstra's algorithm. I call it for each query on the source vertex(dijkstra returns the distance between source and all other vertices) and then return the minimum of these numbers.

const int M = 1000000;
std::unordered_set<int> T;
class Node {
public:
    int endVertex;  // stores the second vertex of the edge
    int weight;     // stores the weight required, it is the weight of the edge
    Node(int end, int weight) {
        this->endVertex = end;
        this->weight = weight;
    }
};

struct NodeComparator {
    bool operator()(const Node &first, const Node &second) {
        return first.weight > second.weight;
    }
};


class Graph {
private:
    std::unordered_map<int, std::vector<Node>> adjacencyList; // it's a vector because there may be repeated Nodes
    int numberOfVertices;

    std::vector<int> dijkstra(int source) {
        std::priority_queue<Node, std::vector<Node>, NodeComparator> heap;
        std::vector<int> distances(this->numberOfVertices, M);
        std::unordered_set<int> visited;
        // distance source->source is 0
        distances[source] = 0;
        heap.emplace(source, 0);
        while (!heap.empty()) {
            int vertex = heap.top().endVertex;
            heap.pop();
            // to avoid repetition
            if (visited.find(vertex) != visited.end()) {
                continue;
            }
            for (Node node: adjacencyList[vertex]) {
                // relaxation
                if (distances[node.endVertex] > distances[vertex]   node.weight) {
                    distances[node.endVertex] = distances[vertex]   node.weight;
                    heap.emplace(node.endVertex, distances[node.endVertex]);
                }
            }
            // mark as visited to avoid going through the same vertex again
            visited.insert(vertex);
        }
        return distances;
    }

    int answer(int source) {
        std::vector<int> distances = this->dijkstra(source);
        std::set<int> answer;
        for (int i: T) {
            answer.insert(distances[i]);
        }
        return *answer.begin();
    }
// other methods
};
// main()

However, my solution does not pass half the tests due to timeout. I replaced my dijkstra method with a Floyd-Warshall algorithm, which directly overrides the starting adjacency matrix, because I thought that the method would be called only once, and then each query would just find the minimum element in the source line of the matrix. This time the timeouts are even worse.

Is there a specific algorithm for efficient queries on shortest path? How can I improve my algorithm?

CodePudding user response:

This seems unnecessary

std::unordered_set<int> visited;

A normal vector does the job faster

std::vector<int> visited(numberOfVertices,0);

so you can replace

if (visited.find(vertex) != visited.end()) {

with the much faster

if( visited[vertex] )

and also

visited.insert(vertex);

becomes

visited[vertex] = 1;

Individual queries can be sped up

replace

    std::set<int> answer;
    for (int i: T) {
        answer.insert(distances[i]);
    }
    return *answer.begin();

with

int shortest = MAX_INT;
for (int d: distances) {
   if( d < shortest ) {
      shortest = d;
   }
}
return shortest;

Modify your dijsktra code to stop searching on a path when it reaches a T node - no need to go any further.

CodePudding user response:

You can reverse all edges and find the shortest path from the set of T (run Dijkstra from all T vertices together) to some vertex S. And precalculate all distances to each S and answer to query in O(1).

  • Related