8

Problem statement: We have an m * n matrix. The starting point is the top left cell. We can only go down or right in the matrix. Destinations are randomly chosen in the matrix. Now we need to find the best routine with the following constraints:

  1. Each node on the route could only have one parent node but could have at most two child nodes.
  2. minimize duplication routes. For example, if we have destinations look like below:

first example

Instead of using the routine on the left-hand side, we should reduce it to the right-hand side one.

  1. prefer going right then down unless going down is shorter than right.

In the example below, instead of choosing the left hand side solution, we should prefer right hand side one as it branches to (2, 1) down by move down from (2, 0) by 1 instead of going right by 2 from (0, 1).

second example

Other examples look like below, which are all best routines.

7 more examples

I'm working on this for a while. I've looked into some algorithms like transitive reduction and Dijkstra, but didn't figure them out. If you would like to give me some hint on algorithms that I could look into that would be great.

Thanks!


Edit 2:

I've received some ideas about Dijkstra algorithm and using dynamic programming. I think for Dijkstra algorithm if you could provide hints for converting this problem to a graph problem that would be great. I was looking into the algorithm and think the primary issue of it is that cells do not have to be visited. In the example below, if we remove one of the destinations, the whole routine would have a significant change comparing to the left-hand side map.

fourth example

For dynamic programming, I have a thought on how a node should join to the path. The priority should look like:

priority graph

But the problem is it fails to consider the problem with a dynamic view, which will output a wrong result.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
Dawen Shi
  • 93
  • 7
  • What's wrong with an ordinary Dijkstra? I'm sure there are better things to do since your network type is very restricted. But Dijkstra should work on any graph, which this is. Wikipedia has a pseudo-code description for it. And if you google you will find complete solutions in any programming language. So where's the problem in using it? Multi-Destination Dijkstra is a super simple modification, just adjust the abort-criteria from one destination to a set of destinations. – Zabuzard Sep 04 '18 at 11:49
  • Hi Zabuza, thank you for your comment. The problem here is how to convert this matrix traverse problem into a graph? Apparently I cannot add every cell in the matrix to the graph as we don't know if we are going to access the cell or not. I don't think it's a straightforward Dijkstra because in Dijkstra the weights of routes are clear, but in my scenario, I need to decide which cell to access. – Dawen Shi Sep 04 '18 at 12:33
  • @DawenShi it is normal in the application of Dijkstra (and other pathfinding) to leave the graph implicit. So you don't build the graph really. – harold Sep 04 '18 at 12:38
  • @zabuza - can you be more specific? The basic rule of Dijkstra is that it does not return back. The problem discussed by author relies on returning back. – libik Sep 04 '18 at 14:41
  • @harold - ^^ same question – libik Sep 04 '18 at 14:42
  • That's why I'm saying be more precise when saying stuff like "*I did not get Dijkstra*". It sounds like you need an explanation or something, not that you think it doesn't work for your specific problem. Try to ask a precise question. After the edits your question got clearer and better :) – Zabuzard Sep 04 '18 at 15:25
  • I don't understand why you chose to get to the third node from the second node, in the second example of the top row of the group of five examples. It seems to me that a route coming down from the top horizontal route should connect with the third node instead. – גלעד ברקן Sep 05 '18 at 01:03
  • @גלעדברקן The reason is that we would prefer getting a node from the left-hand side rather than the top side. If a node could be accessed from both the left-hand side and the top side, you should choose the left-hand side. The last figure shows the priority of which routine to choose. – Dawen Shi Sep 05 '18 at 09:22
  • @DawenShi doesn't that contradict rule 3? "prefer going right then down unless going down is shorter than right." – גלעד ברקן Sep 05 '18 at 09:33
  • @גלעדברקן Firstly I want to check which graph are we talking about. I would specify the starting point as (0, 0), I guess the graph you are talking about is with starting point (0, 0), detinations: (0, 2), (1, 0), (2, 1), (3, 2)? Would you like to tell me what do you mean by 'second node' and 'third node' please? – Dawen Shi Sep 05 '18 at 12:07
  • @DawenShi by "node," I mean `D`. – גלעד ברקן Sep 05 '18 at 13:48
  • Maybe you want to check out [A Survey on Multi-net Global Routing for Integrated Circuits](http://people.ece.umn.edu/~sachin/jnl/integration01.pdf) for a larger view on this problem and maybe you can find a suitable algorithm there. – MicSim Sep 05 '18 at 14:53
  • @MicSim do you have a counter example for my answer? – גלעד ברקן Sep 05 '18 at 15:33
  • @גלעדברקן No, why should I? My comment was targeted at the OP, Dawen Shi. – MicSim Sep 06 '18 at 08:05
  • @MicSim because your comment implies you're not convinced by the current answers :) – גלעד ברקן Sep 06 '18 at 08:06

3 Answers3

1

I think your examples could all fit with the following general algorithm: traversing left and up simultaneously — starting with the ends of the first row and column, followed by the ends of the second row and column, etc. — extend routes from each D encountered to the closest route, D or S (Manhattan distance in the N-NW-W arc, of course).

Example 7:

  1 2 3 4
1 S     D

2     D

3   D

4 D     D

  1 2 3 4
1 S-----D<
  |
2 |   D
  |
3 | D
  |
4 D     D
  ^

  1 2 3 4
1 S-----D
  |   |
2 |   D  <
  |
3 |-D
  |
4 D     D
    ^

  1 2 3 4
1 S-----D
  |   |
2 |   D
  |
3 |-D
  |
4 D-----D<
        ^

Example 5:

  1 2 3 4
1 S

2       D

3     D

4 D     D

  1 2 3 4
1 S      <
  |
2 |     D
  |
3 |   D
  |
4 D     D
  ^

  1 2 3 4
1 S
  |
2 |-----D<
  |
3 |   D
  |
4 D     D
    ^

  1 2 3 4
1 S
  |
2 |-----D
  |   |
3 |   D  <
  |
4 D     D
      ^

  1 2 3 4
1 S
  |
2 |-----D
  |   |
3 |   D--
  |     |
4 D     D<
        ^

Example 1:

  1 2 3 4
1 S

2     D

3   D   D

4     D

  1 2 3 4
1 S--
    |
2   --D  <
    |
3   D   D

4     D
    ^

  1 2 3 4
1 S--
    |
2   --D
    |
3   D---D<
      |
4     D
      ^
גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
  • Thank you for your solution, I think your solution is quite close but I want to know that for the example 5 with your algorithm how did you find the route from point (4, 4) to point (3, 3) by just traversing left or up? – Dawen Shi Sep 05 '18 at 15:37
  • @DawenShi the algorithm describes: "extend route... to the closest route, D or S." (3,3) is the closest D to (4,4). (We know we have to find closest in the N-NW-W arc, of course. Manhattan distance.) – גלעד ברקן Sep 05 '18 at 15:42
  • I guess your algorithm should start from traversing up first? If we traversing from right first then in Example 1 we won't get the routine from (3, 2) to (1, 1) in a correct manner. – Dawen Shi Sep 06 '18 at 10:33
  • @DawenShi the issue in my algorithm is not the exact direction of traversal from each D - what's important is the order the `D`s are encountered and the choice of the closest destination they will route to. What you are asking is more about implementation and handling of individual situations, which I leave for others to work out. – גלעד ברקן Sep 06 '18 at 12:07
0

This is a recursive problem. You should try practicing Greedy Algorithms and Dynamic Programming, and try some categorized followed by some mixed-bag programming questions to give you a better idea about what to apply when, and how to make algorithms that are a combination of the two.

Use a Divide and Conquer approach to solve this. put yourself in the place of the moving cursor, and think about an ordered set of logical actions that you could follow at each node so that you solve the problem.

I will add my algorithm to solve this problem after a few days. This is to ensure that I don't accidentally end up helping someone heat in a competition.

You could refer to this and this to get a little insight into the technique. I also found a fun article related to understanding recursion better. It might not be very informative, but it is definitely motivational.

Hint: There are only 3 possible places where an unvisited destination node could be located for it to be possible to visit:

  1. It is directly below the current node
  2. It is directly to the right of the current node
  3. it is somewhere to the bottom-right side of the current node

A possible algorithm could be that you recursively:

  1. check for a node below you, and visit it immediately via a recursive function call if present.
  2. check for the farthest node present in the current horizontal level, and draw a path to it without a recursive call.

[edit 1 : Sorry, I forgot to mention the default case!!!]

  1. If there is no node in the same horizontal or vertical of the cursor, move right. The algorithm may seem simple to look at but will solve the problem. Its complexity is also only O(N).
  • 1
    Hi, I tried to execute your algorithm in mind, I guess if we have the destination on the far diagonal of the source your algorithm will choose go down first, but it should go right to the end of the first row then goes down. – Dawen Shi Sep 06 '18 at 10:31
  • Just look at the current edit. (SORRY, I forgot to mention the default case!!) –  Sep 12 '18 at 03:55
0

Thank you for all your answers and comments. All of the comments are valuable for me and stimulated my thinking.

I now come up with a solution that takes advantages of the existing Dijkstra algorithm and correct node traversing order. Instead of starting from top left corner, we now make the original source as destination. Then turns all directions backwards so that now we can only go left or up from a node. The solution looks like below:

  1. Build a weighted graph. All going left edges have the weight of 1, all going up edges have the weight of (m + 1 - col), so that the first column of going up routines (with a 4 by 4 matrix) all have the weight of 5. Example weight graph looks like below: enter image description here

  2. Add node (0, 0) to founded routes.

  3. Start from top left node (0, 0), check all the nodes on its right ((0, 0) to (0, n)). Then check all the nodes on its bottom ((1, 0) to (m, 0)). For all the Source node (originally destination node), use Dijkstra algorithm to find its shortest way back to the founded routes, add all nodes in Dijkstra algorithm to founded routes.

  4. Repeat step 3 for all node (i, i) until the last one ((m, m) or (n, n)).

Any other more efficient solutions are highly welcome. Also, if you figured out a pitfall in this algorithm that would be great. This algorithm seems to work but my feeling is that it's not the most effective way.

Dawen Shi
  • 93
  • 7