DZHAMBULAT-SAMOUCHKA
@DZHAMBULAT-SAMOUCHKA
Frontend разработчик

Как найти начальную точку для определения маршрутов в двумерном массиве?

Здраствуйте. Возможно очень странно сформулировал вопрос за это извините. Решая задачу наткнулся на одну проблему. Есть входной двумерный массив с странами:
[["USA", "BRA"], ["JPN", "PHL"], ["BRA", "UAE"], ["UAE", "JPN"]]

Нужно вывести правильную последовательность следования маршрутов объединив элементы массива в одну строку. Вот такой результат должен вывестись:
"USA, BRA, UAE, JPN, PHL"

Всё бы ничего и мой код работал бы (чуть ниже), если бы был известен начальный маршрут от которого нужно отталкиваться. Если поменять местами входные данные то мой код перестаёт выдавать правильную последовательность. Точка начала маршрута у меня находиться в переменной initialRoute. Пример:
[["JPN", "PHL"], ["USA", "BRA"], ["BRA", "UAE"], ["UAE", "JPN"]],
Вывод: "JPN, PHL"


Вот мой код
function findRoutes(routes) {
  const dictionary = {};
  // Точка начала маршрута 
  const initialRoute = routes[0][0];
  const stack = [initialRoute];

  routes.forEach((el) => {
    dictionary[el[0]] = el[1];
  });

  function checkRoutesPos(dictionary, initialRoute) {
    let thisRoute = initialRoute;
    let pushElem = dictionary[thisRoute];
    while (pushElem !== undefined) {
      thisRoute = dictionary[thisRoute];
      stack.push(pushElem);
      pushElem = dictionary[thisRoute];
    }
  }
  checkRoutesPos(dictionary, initialRoute);
  return stack.join(", ");
}
console.log(
  findRoutes([
    ["USA", "BRA"],
    ["JPN", "PHL"],
    ["BRA", "UAE"],
    ["UAE", "JPN"],
  ])
);
console.log(
  findRoutes([
    ["JPN", "PHL"],
    ["USA", "BRA"],
    ["BRA", "UAE"],
    ["UAE", "JPN"],
  ])
);
  • Вопрос задан
  • 228 просмотров
Решения вопроса 1
Tim-A-2020
@Tim-A-2020
function findSequence(input) {
    const adjacencyList = {}, indegree = {};

    input.forEach(([from, to]) => {
        adjacencyList[from] = (adjacencyList[from] || []).concat(to);
        indegree[to] = (indegree[to] || 0) + 1;
    });

    const start = Object.keys(adjacencyList).find(country => !indegree[country]);
    if (!start) {
        return false;
    }

    const result = [], visited = {};

    function dfs(node) {
        visited[node] = true;
        result.push(node);
        adjacencyList[node]?.forEach(neighbor => !visited[neighbor] && dfs(neighbor));
    }

    dfs(start);
    return result.join(', ');
}
findSequence([["USA", "BRA"], ["JPN", "PHL"], ["BRA", "UAE"], ["UAE", "JPN"]])//"USA, BRA, UAE, JPN, PHL"
Ответ написан
Пригласить эксперта
Ответы на вопрос 5
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
В общем случае - теория графов, Эйлеров путь.
Для случая, когда путь заведомо есть, он только один и проходит через каждую вершину только один раз, ищем вершину, для которой есть исходящий маршрут, но нет входящих.
В вашем примере это "USA". Есть маршрут, который с неё начинается, но нет маршрута, который в ней заканчивается.
Ответ написан
@Akina
Сетевой и системный админ, SQL-программист.
Всё бы ничего и мой код работал бы (чуть ниже), если бы был известен начальный маршрут от которого нужно отталкиваться.

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

Применительно к показанному массиву - только значение USA соответствует описанному условию.

А ещё - обязательно проверяйтесь на цикл. Например, исходные (А,Б),(Б,В),(В,Б) отправят вашу программу в нирвану... Как вариант, можно просто исключать уже использованные элементы из дальнейших итераций.
Ответ написан
muscimolus
@muscimolus
const routes = [
    ['USA', 'BRA'], ['JPN', 'PHL'], ['BRA', 'UAE'], ['UAE', 'JPN']
]

const length = routes.length
const start = routes.shift()
const chain = [ start ]

while(chain.length !== length){
    const [ _, to ] = chain[ chain.length -1 ]
    routes.forEach(([ from ], index) => {
        if(to === from){
            chain.push(routes[index])
        }
    })
}

const set = new Set()

chain.forEach(([ from, to ]) => set.add(from).add(to))

const route = []

set.forEach(any => route.push(any))

const string = route.join(',')

console.log(string)


Так?

P.S.: Пропустил, что в строку надо, поправил.
Ну и это не сработает с вариантом, когда ты отправной точкой (start) будешь объявлять массив, значение to (второе) которого не присутствует в from (первом значении) других массивов.

Если ты ниндзя

const data = [
    ['A', 'B'], ['O', 'P'], // [начало], [конец (возможно)]
    ['E', 'F'], ['J', 'K'],
    ['F', 'G'], ['K', 'L'],
    ['N', 'O'], ['M', 'N'],
    ['L', 'M'], ['G', 'H'],
    ['B', 'C'], ['H', 'I'],
    ['M', 'N'], ['C', 'D'],
    ['D', 'E'], ['I', 'J']
]

const [ length, chain, [ start, end ], routes ] = [ data.length, [ ], [ ...data ], data.slice(2) ]

chain.push(start)

while(chain.length !== length -1){
    const [ , to ] = chain[ chain.length -1 ]
    routes.forEach(([ from ], index) => to === from ? chain.push(routes[ index ]) : void(0))
}

chain.push(end)

console.log(chain.map(([ from, to ], index) => index === chain.length -1 ? [ from, to ].join(',') : from).join(', '))

Ответ написан
hint000
@hint000
у админа три руки
От исходной точки можно искать не только вперёд, но и назад.
Ответ написан
@StockholmSyndrome
function findRoute(arr) {
    const map = arr.reduce((acc, [from, to]) => (acc[from] = to, acc), {})  
    const result = []
    let curr = arr[0][0]
    while (curr) {
        result.push(curr)
        curr = map[curr]
    }
    return result
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы