0

I'd like to get output from input.
It should be passed all the ways that is possible but shouldn't be passed the way which was already visited.
It looks similar with Depth-First Search but this should be returned to parent node and then search again.
The logic is the last element of one node should be the same with the first element of another node.
And it should start with 0 and finish when there is no more node for searching.

input = [  
  [0, 1],
  [0, 2],
  [1, 5],
  [2, 6],
  [2, 12],
  [5, 29],
  [6, 29],
  [9, 30],
  [12, 18],
  [18, 29],
  [29, 9],
  [29, 12],
  [29, 18]
];

output =  [
  [0,1,5,29,9,30],
  [0,1,5,29,12,18,29,18],
  [0,1,5,29,12,18,29,9,30],
  [0,1,5,29,18,29,9,30],
  [0,1,5,29,18,29,12,18],
  [0,2,6,29,9,30],
  [0,2,6,29,12,18,29,9,30],
  [0,2,6,29,12,18,29,18],
  [0,2,6,29,18,29,9,30],
  [0,2,6,29,18,29,12,18],
  [0,2,12,18,29,9,30],
  [0,2,12,18,29,12],
  [0,2,12,18,29,18]
]

I tried recursion like below and it showed undefined. Setting for visited object seems making undefined, but it showed maximum call stack if I edited it.
(It doesn't matter either recursive or iterative ways to solve this problem.)

Please please help. Any comment would be helpful.

const seeds = input.filter( ele => ele[0] === 0);
const nodes = input.filter( ele => ele[0] !== 0);
const visited = {};

function chain(seed, nodes){
  let result = nodes.map(node => {
    if(node[0] === seed[seed.length - 1]){
      while(!visited[node]){
        visited[node]= true;
        return chain([...seed, node[0]], nodes)
      }
    }
  })
  return result;
}

function getResult(seeds, nodes){
  let result = seeds.map( seed => {
  visited[seed] = true;
    return chain(seed, nodes);
  }).flat();
  return result;
}
devdev
  • 3
  • 4
  • What is the logic? Why is [0, 1, 5, 29, 12, 18, 29, 18] not in the results? – trincot Nov 02 '21 at 19:08
  • You add nodes to `visited` but you never check them before including them in the path. Also, you will probably need a `Set` rather than an `Object` for `visited`. Objects cannot have arrays as keys. – Scott Sauyet Nov 02 '21 at 20:00
  • @trincot the logic is the last element of one node should be the same with the first element of another node. And it should finish when there is no more node for searching. [0, 1, 5, 29, 12, 18, 29, 18] is not complete yet because 18(the last element) is the same with the first element of [18,29]. – devdev Nov 03 '21 at 02:20
  • @ScottSauyet I edited code for visited. And I'll check `Set` to solve this issue. Thanks for your comment! – devdev Nov 03 '21 at 02:30
  • I understand the logic you explained, but I don't see how it doesn't apply to the example. You write "[0, 1, 5, 29, 12, 18, 29, 18] is not complete yet...". Then my question is: how would you complete it? Also: could you give feedback to the answer I posted? – trincot Nov 03 '21 at 07:02
  • 1
    You changed your question a lot in terms of expected output. Why is [0,2,6,12,18,29,9,30] in the desired results, as there is no edge from 6 to 12? Why is [0,2,6,12,18,29,12,18,29,9,30] in the desired results, as it uses the way from 18 to 29 twice, which you write is not allowed? Why is [2,6,29,18,29,12] not in the list? Why is [2,12,18,29,18] not in the list? You really have to be more precise about the requirements... – trincot Nov 04 '21 at 11:03

1 Answers1

2

I assume your graph is a directed graph, and a "way" will use one particular edge only once.

I would suggest building an adjacency list first. One that is keyed by vertices, and for each of them has an array of edges (not neighboring vertices alone).

Then in the DFS you can collect the edges that you visit as you go deeper in the tree, and then test that a new edge can only be added to that list when it does not yet occur in that chain yet. This is the major difference with the "normal" DFS procedure, where you would collect vertices (instead of edges) as you build a path.

Here is the implementation with a generator:

function* dfs(adj, vertex=0, path=[]) {
    let leaf = true;
    for (let edge of adj[vertex]) {
        if (!path.includes(edge)) {
             yield* dfs(adj, edge[1], path.concat([edge]));
             leaf = false;
        }
    }
    if (leaf) yield path.map(edge => edge[0]).concat(vertex);
}

const input = [[0, 1], [0, 2], [1, 5], [2, 6], [2, 12], [5, 29], [6, 29], [9, 30], [12, 18], [18, 29], [29, 9], [29, 12], [29, 18]];

// Build adjacency list as key/value pairs, where key=vertex, 
//    and value=array of outgoing edges (not just the neighbors)
const adj = {};
for (let edge of input) {
    (adj[edge[0]] ??= []).push(edge);
    adj[edge[1]] ??= [];
}

// Output paths
for (let path of dfs(adj)) console.log(JSON.stringify(path));

The input graph is your graph:

enter image description here

The output is:

[0,1,5,29,9,30]
[0,1,5,29,12,18,29,9,30]
[0,1,5,29,12,18,29,18]
[0,1,5,29,18,29,9,30]
[0,1,5,29,18,29,12,18]
[0,2,6,29,9,30]
[0,2,6,29,12,18,29,9,30]
[0,2,6,29,12,18,29,18]
[0,2,6,29,18,29,9,30]
[0,2,6,29,18,29,12,18]
[0,2,12,18,29,9,30]
[0,2,12,18,29,12]
[0,2,12,18,29,18]
trincot
  • 317,000
  • 35
  • 244
  • 286
  • I would appreciate your comment. And I found my mistakes so edited the output of original question. sorry for the inconvenience. The rule is passing all possible path but not duplicately. And it shoud be finished if there is no more unvisited path. That's why [0, 1, 5, 29, 12, 18, 29, 18] have more path to search([18,29],[29,9],[9,30] and it's not included in desired output. – devdev Nov 04 '21 at 10:34
  • I don't understand this. It is a contradiction. You say that there are more paths for this example, and list [18,29]. But you also write that that it should be finished if there is no more unvisited path, but [18,29] was visited! So there is no more unvisited path when you end like that in 18... See also my other comment below your question. You really need to explain your requirements in a more precise way. – trincot Nov 04 '21 at 11:05
  • I am really ashamed of my fault and thank you for your advice. I agree my requirements were not enough at all. I fixed the desired output of the original post and added the output should start 0. And there is an error with my comment. [18,29] should be exempt because [0,1,5,29,12,18,29,18] has [18,29]. I would apologize for this contradiction. – devdev Nov 04 '21 at 14:33
  • OK, now I still have two cases in my output, which you don't have in your desired output: [0,1,5,29,12,18,29,18] and [0,2,12,18,29,12,18,29,18]. Can you explain why you do not want those in the output? Or is it a mistake? – trincot Nov 04 '21 at 15:00
  • Sorry. That was my fault. I added [0,1,5,29,12,18,29,18] in the output. ([0,2,12,18,29,12,18,29,18] was in the output) – devdev Nov 04 '21 at 15:10
  • 1
    I fixed it. I really appreciate your feedback!! – devdev Nov 04 '21 at 17:44