3

You have N nodes, labeled 1…N (N <= 50000). Each node has a designated ID in the range 1…M, where M is at most 50. You are trying to find the shortest path from 1 to N.

You are also given a matrix M x M, to determine if there is are directed edges between nodes of different IDs. M_ij = ‘Y’ if a node of ID i has a directed edge to a node of ID j, and ’N’ if not. Note that M_ij may not equal M_ji, and that M_ii could be = 0.

If there is an edge between two nodes, then the weight of the directed edge between them is the difference between their labels.

Example:

There are 5 nodes.

Node 1: ID 1

Node 2: ID 4

Node 3: ID 2

Node 4: ID 3

Node 5: ID 4

Matrix:

YNYN

NNNY

NYYN

NYNN

So in this matrix, we know that nodes of ID 1 have directed edges to nodes of ID 1 and ID 3. Nodes of ID 2 have directed edges to nodes of ID 4. Nodes of ID 3 have directed edges to nodes of ID 2 and ID 3. And nodes of ID 4 have directed edges to nodes of ID 2.

The answer = 6.

The shortest path between Nodes 1 and 5 is through a directed edge from Node 1 to Node 4, of weight 4 - 1 = 3. Note that this edge is possible because Node 1 is of ID 1, and Node 4 is of ID 3, and nodes of ID 1 have directed edges to all nodes of ID 3. Next, you would use the directed edge from Node 4 to Node 3, of weight 4 - 3 = 1; then the directed edge from Node 3 to Node 5, of weight 5 - 3 = 2. 3 + 1 + 2 = 6, so the total shortest path is 6.

My solution:

When I first read this problem, I thought that Dijkstra’s algorithm would solve it easily. However, its time complexity is N^2logN, and the number of edges could be at most 50000^2 which is too high. How can I solve the shortest path problem in a dense graph? Is there a way to optimize Dijkstra by utilizing the matrix in some way?

cracra
  • 107
  • 11
  • So the `ID` -- despite its name -- is not necessarily unique? Another name for this attribute would be appropriate then... – trincot Jan 23 '21 at 09:24
  • *"we know that nodes of ID 1 have directed edges to nodes of ID 1 and ID 3"*: can this statement be more explicit? Does it mean ALL nodes of ID 1 have directed edges to ALL nodes of ID 1 and ALL nodes of ID 3? Or does it mean that SOME nodes of ID 1 have directed edges to SOME nodes of ID 1 and SOME nodes of ID 3? – trincot Jan 23 '21 at 09:34
  • If I understand the question correctly, then better terms would be `position` 1 to N, and `group` 1 to M. The distance is the absolute difference between `positions`. The matrix represents edges between `groups`. The path in the questions uses `positions` 1,4,3,5. The net distance travelled is 5-1=4, but because of the backtracking from position 4 to 3, an additional distance of 2 is added, bringing the total path length to 6. In other words, the goal is to minimize backtracking. IMO, Dijkstra won't help with that at all. – user3386109 Jan 23 '21 at 10:52

3 Answers3

2

Lets say there are 3 nodes with different labels who share the same id 1:
ID 1 <==> Labels {1, 7, 13}

Similary, there are 5 nodes who share the same id 2:
ID 2 <==> Labels {2, 8, 12, 15}

3 nodes who share the same id 3:
ID 3 <==> Labels {5, 10, 11}

and 2 nodes who share the same id 4:
ID 4 <==> Labels {6, 9}

Now lets say we have 4 edges:

  • ID1 -> ID2
  • ID1 -> ID3
  • ID2 -> ID4
  • ID3 -> ID4

If we want to find out the smallest distance between labels '7' and '9', how would we do it?

Well label 7 means ID1 and label 9 means ID4. That means we need to find the shortest distance between ID1 and ID4.

But since there is no direct edge between these 2 ids, we would have to jump to ID 2 or 3 first.

Lets calculate the distance to ID 2:
Which label should we jump to within ID2 from ID1?
Since distance is defined as the absolute difference between 2 label values, and source label is '7', we should jump at a label which is closest to value to 7.
Among {1, 2, 8, 12, 15}, this would be '8' (distance = 8-7 = 1)

Lets calculate the distance to ID 3:
Which label should we jump to within ID3 from ID1?
Among {5, 10, 11}, the number closest to 7 would be '5' (distance = 7-5 = 2)

Since distance to ID2 is smaller than ID3, we should jump to ID2, label 8.

Now that we are at label 8, we can directly jump to label 9 in ID4 (distance = 9-8 = 1)

Total distance = 1 + min(1, 2) + 1 = 3

The general algorithm would be:

  • Create a hashmap between ID and a sorted list of labels who share that ID.
  • If source label is L1 and destination label is L2, assuming they belong to ids I1 and I2, perform dijkstra to find shortest distance between ids I1 and I2.
  • While performing dijkstra, compute the 'distance' between current label 'L1' and a neighbour id by choosing the label which is closest in value to L1 among the list of labels sharing that id (this list can be accessed from the hashmap).
  • For all such distances from L1 to the neighbour IDs, push all these distances (along with the chosen label) to a priority queue (same as normal dijkstra).

Finding a number closest to a value in a sorted array can be done in O(logn), where n is the size of the sorted array.

The algorithmic complexity for dijkstra would be O(M^2 * logM * logX), where X = average number of labels sharing a single ID, which can be safely assumed to be N / M.

Creating hashmap with sorted lists would take O(M*X*logX) = O(N * logN/M) complexity.

So total complexity = O((N * log(N/M)) + (M^2 * logM * log(N/M)) ~ O(log(N/M) * (N + M^2)

Anmol Singh Jaggi
  • 8,376
  • 4
  • 36
  • 77
  • Creating the hashmap is O(N) which kills the rest of the effective implementation though - you need to look at each node at least once to add it into the hashmap. – Shamis Jan 23 '21 at 09:49
  • @Shamis Thanks for pointing out. Fixed the complexity calculation. – Anmol Singh Jaggi Jan 23 '21 at 09:52
1

Disclaimer:
As I understand your formulation, edge ID1 -> ID2 means that from a node with ID1 there is an edge to every other node with ID2. If this is not correct, simply ignore the rest. For now I will assume this to be the truth.

Observation:
Since the edge ID1->ID2 means that every node with ID1 has an edge to every other node with ID2 it doesn't matter which node with certain ID we use - they are all equivalent for the shortest path purpose.
This means that to compute the length of the shortest path from a node Label_X, ID_I to a node Label_Y, ID_J we can simply compute the Djikstra over a graph that considers every label present exactly once to find a shortest path over labels. This will take O(M * log(M^2)) operations.

Now, since we have the path of labels we can simply select a first node, with the required label, that we encountered. Since we have to read the input anyways, we can simply create an array with a first node of every ID that we encounter. The reading of the input will take ~ N + M^2 operations
The total complexity in this case would be O(N + M^2 + M * log(M^2)). In your case the total would be 50000 + 2500 + 50 * log(2500) = ~ 53100.

Shamis
  • 2,544
  • 10
  • 16
  • not sure how the last sentence is ruining anything. It is an approximate count of steps you will be taking in the worst case with the information the OP provided. – Shamis Jan 23 '21 at 16:37
0

Run Dijkstra's algorithm on the smaller graph with M nodes, not the bigger graph with N nodes i.e. treat each designated ID as a node, and solve the problem on that graph.

For example, if node 1 has designated ID of A, and node N has designated ID of B, solve the shortest path from A to B using the edge information given by the M by M matrix. Constructing the path is easy - just pick any "real" node from each "meta" designated ID nodes in the path.

The time complexity of Dijkstra's algorithm depends on the data structure used for the frontier set. Since you claim that it is a "dense" graph (which usually means the number of edges is proportional to the square of number of nodes), using this method will give you O(M^2logM) if you use a binary mean heap. It will be O(M^2) if you use an unsorted array, which will be better for dense graphs.

Note that this method only works because when M_ij = Y, ALL nodes with designated ID of i have outgoing edges to ALL nodes with designated ID of j.

wookie919
  • 3,054
  • 24
  • 32