Как создавать пути из заданных узлов без пункта назначения - PullRequest
0 голосов
/ 23 сентября 2018

Я нашел возможные ходы фигуры и сохранил в следующем массиве.

var moves = [ {from: 67 , to:35} , {from: 35 , to:3} , {from: 35 , to:37} , {from: 35 , to:33} , {from: 37 , to:5} , {from: 37 , to:39} , {from: 33 , to:1} ,{from: 39 , to:7} ] ; 

Теперь мне нужно создать следующие пути из этих ходов.

var path1= [{from:67, to:35} , {from:35, to:3}];
var path2= [{from:67, to:35} , {from:35, to:37} ,  {from:37, to:5} ];
var path3= [{from:67, to:35} , {from:35, to:33} ,  {from:33, to:1}];
var path4= [{from:67, to:35} , {from:35, to:37} ,  {from:37, to:39} ,  {from:39, to:7} ];

Я сделалнекоторый код для создания массива путей, но это не то, что мне нужно, может кто-нибудь помочь с созданием путей.

Я не могу использовать DFS или BFS, потому что у меня нет пункта назначения.

function GetPaths(moves,possiblePaths) {
    var paths = [];
    var allmoves=[];
    for (var x = 0 ; x < moves.length ; x++) {
        var path = [];
        var move = [];
        var data2 = [];
        data2.push([moves[x].from, moves[x].to]);
        for (var y = x + 1 ; y < moves.length ; y++) {
            if (moves[x].to == moves[y].from) {

                if (!(path.includes(data2[0]))) {
                    path.push(data2[0]);
                    move.push(moves[x]);
                }
                var data = [moves[y].from, moves[y].to];
                path.push(data);
                move.push(moves[y]);
            }
        }
        if (path.length > 0) paths.push(path);
        if (move.length > 0) {
            allmoves.push(move);
        }



    }
    if (paths.length>1) {

    var newpaths = [];
    var newmoves =[];
    var nextRow = paths[0];
    var nextmove = allmoves[0];
    var len = paths.length;


    for (var h = 1 ; h < nextRow.length; h++) {

        for (var j = 1 ; j < len ; j++) {
            var newpath = [];
            var newmove =[];
            if (isInArray(nextRow[h], paths[j][0])) {

                newpath.push(nextRow[0]);
                 newmove.push(nextmove[0]);
                var nextfound = false;
                for (var k = j + 1 ; k < paths.length ; k++) {
                    if (isInArray(paths[j][paths[j].length - 1], paths[k][0])) {
                        newpath.push(paths[j][0]);
                        if (paths[k][0][0] - paths[k][0][1] != -(paths[k][1][0] - paths[k][1][1])) {
                            newpath.push(paths[k]);
                            newmove.push(allmoves[k]);
                        } else {
                            newpath.push(paths[k][0]);
                            newmove.push(allmoves[k][0]);
                        }

                        nextfound = true;
                    }

                }
                if (!nextfound) {
                    newpath.push(paths[j]);
                    newmove.push(allmoves[j]);
                }

            }
            if (newpath.length > 0) {
                newpaths.push(newpath);
                newmoves.push(newmove);
            }
        }

    }

    return newmoves;
    }
    return allmoves;
}

Приведенный ниже ответ работает для приведенного выше примера, но не работает для приведенного ниже примера

84–52, 52–20, 52–54, 52–50, 20 ––22, 20–18, 54–22, 50–18, 22–20, 18–20, 20–18, 20–22

, которые имеют следующие пути

1) 84 52,52 20, 20 18

2) 84 52, 52 20, 20 22 * ​​1020 *

3) 84 52, 52 54, 54 22, 22 20, 20 18

4) 84 52, 52 50, 50 18, 18 20, 20 22 * ​​1024 *

График для этого.

enter image description here

1 Ответ

0 голосов
/ 23 сентября 2018

Первый пример - это проблема обхода дерева : найти каждый путь, заданный корнем ко всем его листьям (узлам-потомкам, у которых нет дочерних элементов).

Чтобы выполнить обход, это помогает поместить дерево в форму, которая позволяет быстро искать детей по заданному родителю.После поиска нам нужно преобразовать полученные пути в запрошенный вами формат.

Вот дерево:

     67
     |
     35
   / | \  
  3  37 33
    / \   \
   5   39  1
        \
         7

Решение такое же, как в DFS / BFSза исключением того, что вместо возврата после того, как листовой узел найден, вычислите его путь обратно к корню, добавьте его в список основных путей и продолжайте поиск в остальной части дерева.

const pathsToLeaves = (root, tree) => {
  const parent = {root: null};
  const stack = [root];
  const paths = [];
  
  while (stack.length) {
    let curr = stack.pop();
    
    if (curr in tree) {
      for (const child of tree[curr]) {
        stack.push(child);
        parent[child] = curr;
      }
    }
    else {
      const path = [];
      
      while (curr) {
        path.unshift(curr);
        curr = parent[curr];
      }
      
      paths.push(path);
    }
  }
  
  return paths;
};


const movesToTree = moves => 
  moves.reduce((a, e) => {
    if (!(e.from in a)) {
      a[e.from] = [];
    }

    a[e.from].push(e.to);
    return a;
  }, {})
;

const pathsToMoves = paths => 
  paths.map(f => f.reduce((a, e, i) => {
    if (a === null) {
      a = [{from: e}];
    }
    else if (i < f.length - 1) {
      a[a.length-1].to = e;
      a.push({from: e});
    }
    else {
      a[a.length-1].to = e;
    }

    return a;
  }, null))
;

const getPaths = (from, moves) => 
  pathsToMoves(pathsToLeaves(from, movesToTree(moves)))
;

const moves = [
  {from: 67, to: 35}, 
  {from: 35, to: 3}, 
  {from: 35, to: 37}, 
  {from: 35, to: 33}, 
  {from: 37, to: 5}, 
  {from: 37, to: 39}, 
  {from: 33, to: 1},
  {from: 39, to: 7}
]; 

console.log(getPaths(67, moves));

Второй опубликованный вами пример - циклический мультиграф.Все еще возможно получить все запрошенные вами пути, но алгоритм намного менее эффективен, чем древовидная версия, из-за предварительной обработки для удаления параллельных ребер в мультиграфе, преобразования в / из желаемого формата и копирования массива / объекта во времяобход.Многие из этих ударов скорости могут быть оптимизированы с использованием различных подходов, но вот базовая версия:

const pathsFrom = (src, graph) => {
  const stack = [[src, [], {}]];
  const paths = [];
  
  while (stack.length) {
    const [curr, path, visited] = stack.pop();
    
    if (curr in graph && !(curr in visited)) {
      visited[curr] = 1;
      path.push(curr);
      let pathFollowed = false;

      for (const neighbor of graph[curr]) {
        if (!(neighbor in visited)) {
          pathFollowed = true;

          const visitedCpy = Object.keys(visited).reduce((a, e) => {
            a[e] = visited[e];
            return a;
          }, {});
          stack.push([neighbor, path.slice(0), visitedCpy]);
        }
      }

      if (!pathFollowed) {
        paths.push(path);
      }
    }
    else {
      paths.push(path.concat(curr));
    }
  }
  
  return paths;
};

const movesToGraph = moves => 
  moves.reduce((a, e) => {
    if (!(e.from in a)) {
      a[e.from] = [];
    }

    a[e.from].push(e.to);
    return a;
  }, {})
;

const pathsToMoves = paths => 
  paths.map(f => f.reduce((a, e, i) => {
    if (a === null) {
      a = [{from: e}];
    }
    else if (i < f.length - 1) {
      a[a.length-1].to = e;
      a.push({from: e});
    }
    else {
      a[a.length-1].to = e;
    }

    return a;
  }, null))
;

const dedupe = a =>
  Object.values(a.reduce((a, e) => {
    const key = `${e.from} ${e.to}`;

    if (!(key in a)) {
      a[key] = e;
    }

    return a;
  }, {}))
;

const getPaths = (from, moves) => 
  pathsToMoves(pathsFrom(from, movesToGraph(dedupe(moves)), [], []))
;

[
  [
    {from: 67, to: 35}, 
    {from: 35, to: 3}, 
    {from: 35, to: 37}, 
    {from: 35, to: 33}, 
    {from: 37, to: 5}, 
    {from: 37, to: 39}, 
    {from: 33, to: 1},
    {from: 39, to: 7}
  ],
  [
    {from: 84, to: 52}, 
    {from: 52, to: 20}, 
    {from: 52, to: 54}, 
    {from: 52, to: 50}, 
    {from: 20, to: 22}, 
    {from: 20, to: 18}, 
    {from: 54, to: 22},
    {from: 50, to: 18},
    {from: 22, to: 20},
    {from: 18, to: 20},
    {from: 20, to: 18},
    {from: 20, to: 22},
  ]
].forEach(test => console.log(getPaths(test[0].from, test)));
...