Hints for SRM 519, D2, 600-Pointer (ThreeTeleports) using Dijkstra's Algorithm

James S. Plank

Fri Nov 1 15:12:46 EDT 2013
Problem Statement.
This is a great opportunity for you to practice using Dijkstra's algorithm. Your first order of business is to turn the problem into a graph problem. You have eight nodes on your graph: { Me, Home, T1A, T1B, T2A, T2B, T3A and T3B }. The graph is a complete graph -- the edge weights between T1A-T1B, T2A-T2B, T3A-T3B are 10. Otherwise, the edge weights are the number of hops that it takes to get between the nodes' grid points.

Let's take a look at the graphs for the first example. I'm not drawing the nodes on the grid -- I'm just drawing them as a graph. You should verify that the weights of the edges make sense. I draw purple edges out of node 0, turquoise edges out of node 1, red edges for intra-teleport edges (these are the ones whose weights are ten), and green edges for inter-teleport edges.

We're going to run Dijstra's shortest path algorithm on this starting at node zero, and ending at node 1, and in this example, that runs really quickly, because the smallest edge out of node zero goes to node 1. We're done, and the path length equals three.

Here's the second example:

As you can see now, the shortest path goes through Teleport 1, and has a path length of 14.


Coding it up

You should work in phases. In phase one, simply create the nodes and store their X and Y values. Return 0 so it compiles: Here's my program printing them out for examples 0 and 1:
UNIX> a.out 0
Node 0: x: 3 y: 3
Node 1: x: 4 y: 5
Node 2: x: 1000 y: 1001
Node 3: x: 1000 y: 1002
Node 4: x: 1000 y: 1003
Node 5: x: 1000 y: 1004
Node 6: x: 1000 y: 1005
Node 7: x: 1000 y: 1006

0
UNIX> a.out 1
Node 0: x: 0 y: 0
Node 1: x: 20 y: 20
Node 2: x: 1 y: 1
Node 3: x: 18 y: 20
Node 4: x: 1000 y: 1003
Node 5: x: 1000 y: 1004
Node 6: x: 1000 y: 1005
Node 7: x: 1000 y: 1006

0
UNIX> 
Next, go and create the adjacency lists, or the adjacency matrix (that's what I did), and print that out:
UNIX> a.out 0
Node 0:          0          3       1995       1996       1997       1998       1999       2000
Node 1:          3          0       1992       1993       1994       1995       1996       1997
Node 2:       1995       1992          0         10          2          3          4          5
Node 3:       1996       1993         10          0          1          2          3          4
Node 4:       1997       1994          2          1          0         10          2          3
Node 5:       1998       1995          3          2         10          0          1          2
Node 6:       1999       1996          4          3          2          1          0         10
Node 7:       2000       1997          5          4          3          2         10          0
0
UNIX> a.out 1
Node 0:          0         40          2         38       2003       2004       2005       2006
Node 1:         40          0         38          2       1963       1964       1965       1966
Node 2:          2         38          0         10       2001       2002       2003       2004
Node 3:         38          2         10          0       1965       1966       1967       1968
Node 4:       2003       1963       2001       1965          0         10          2          3
Node 5:       2004       1964       2002       1966         10          0          1          2
Node 6:       2005       1965       2003       1967          2          1          0         10
Node 7:       2006       1966       2004       1968          3          2         10          0
0
UNIX> 
And finally, do your Dijkstra algorithm. I hold a distance field in each node, and start with all of the equal to -1. I then set node's distance to 0 and put it onto the multimap. Then, I process the multimap. When I process edges, I put a node onto the multimap when the distance to that node is either the first known distance, or if it is less than the best distance so far. When I put a node on the multimap, I don't delete previous instances of the node on the multimap -- I simply ignore those when I encounter them.

Here is the multimap and its processing for examples 0 and 1:

UNIX> a.out 0
Multimap:
   [Node:0,Dist:0]

Shortest path to 0 is 0

Multimap:
   [Node:1,Dist:3]
   [Node:2,Dist:1995]
   [Node:3,Dist:1996]
   [Node:4,Dist:1997]
   [Node:5,Dist:1998]
   [Node:6,Dist:1999]
   [Node:7,Dist:2000]

Shortest path to 1 is 3
3
Multimap:
   [Node:0,Dist:0]

Shortest path to 0 is 0

Multimap:
   [Node:2,Dist:2]
   [Node:3,Dist:38]
   [Node:1,Dist:40]
   [Node:4,Dist:2003]
   [Node:5,Dist:2004]
   [Node:6,Dist:2005]
   [Node:7,Dist:2006]

Shortest path to 2 is 2

Multimap:      You'll note that Node 3 is on twice.  I didn't delete the old one.
   [Node:3,Dist:12]
   [Node:3,Dist:38]
   [Node:1,Dist:40]
   [Node:4,Dist:2003]
   [Node:5,Dist:2004]
   [Node:6,Dist:2005]
   [Node:7,Dist:2006]

Shortest path to 3 is 12

Multimap:
   [Node:1,Dist:14]
   [Node:3,Dist:38]
   [Node:1,Dist:40]
   [Node:4,Dist:1977]
   [Node:5,Dist:1978]
   [Node:6,Dist:1979]
   [Node:7,Dist:1980]
   [Node:4,Dist:2003]
   [Node:5,Dist:2004]
   [Node:6,Dist:2005]
   [Node:7,Dist:2006]

Shortest path to 1 is 14
14
UNIX> 

Compile, test, submit! Oh -- and use long long's for those distances -- the total path length's can be greater than 231. Yuck.