Какой алгоритм я могу использовать для поиска кратчайшего пути между указанными типами узлов в графе?

Это проблема:

У меня есть n точек (p1, p2, p3, .. pn), каждая из них может соединиться с любой другой с определенной стоимостью x.

Каждая точка принадлежит к одному из множества типов точек (например, "A", "B", "C", "D"...).

Ввод метода - это путь, по которому я хочу следовать, например, «A-B-C-A-D-B».

Выход - это кратчайший путь, соединяющий точки типа, который я даю на входе, например, "p1-p4-p32-p83-p43-p12", где p1 - тип A, p4 - тип B, p32 - тип C-. тип, p83 тип A, p43 тип D и p12 тип B.

«Простое» решение состоит в вычислении ВСЕХ возможных путей, но вычислительная стоимость очень высока!

Может ли кто-нибудь найти лучший алгоритм?

Как я сказал в заголовке, я не знаю, существует ли он!

Обновлять:

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

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

Это изображение Кента Фредрика (большое спасибо), которое описывает исходную ситуацию (разрешенные ссылки выделены красным цветом)!

альтернативный текст

Пример из реальной жизни:

Человек хочет посетить церковь утром, пойти в ресторан и, наконец, посетить музей днем.

На карте 6 церквей, 30 ресторанов и 4 музея.

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


person Alberto    schedule 17.07.2009    source источник
comment
Я не понимаю, что именно вы имеете в виду. Разве это не просто какое-то минимальное остовное дерево?   -  person mmx    schedule 17.07.2009
comment
Планируете ли вы продавать что-либо в любой из этих точек? en.wikipedia.org/wiki/Travelling_salesman_problem   -  person Andrew Hare    schedule 17.07.2009
comment
Подождите, вы можете следить только за одним узлом для каждой буквы?   -  person EFraim    schedule 17.07.2009
comment
@EFraim: У меня сложилось впечатление, что существует несколько узлов каждого буквенного типа.   -  person chaos    schedule 17.07.2009
comment
@chaos: на самом деле вопрос в том, представляет ли одна буква путь или узел. Я дал два решения, которые, надеюсь, решат оба случая.   -  person EFraim    schedule 17.07.2009
comment
Вопрос требует уточнения: каждая точка принадлежит набору, что вводит в заблуждение, вы, вероятно, хотите сказать что-то вроде того, что каждая точка принадлежит набору типов точек.   -  person RBarryYoung    schedule 17.07.2009
comment
@EFraim: О, понятно. Разве буква не представляет тип узла? Например, я могу находиться в точке p22, которая имеет вершины в точках p27 (A), p58 (B), p66 (D) и p93 (D), и моими полезными вариантами являются вершины в точках P66 и P93, потому что ограничение пути имеет D в качестве следующего элемента.   -  person chaos    schedule 17.07.2009
comment
Трудно понять вопрос, если вы можете привести наглядный пример системы узлов, представляющей образец набора данных, это было бы неизмеримо полезно.   -  person Kent Fredric    schedule 17.07.2009
comment
Я обновил вопрос, прошу прощения за мой английский...   -  person Alberto    schedule 17.07.2009
comment
Эндрю Хэйр: Пожалуйста, скажите мне, что это иронично.   -  person RBarryYoung    schedule 17.07.2009
comment
Альберто, на самом деле неясно, разрешено ли вам повторно посещать узел, чтобы удовлетворить ограничение пути. Может помочь прояснить это.   -  person chaos    schedule 17.07.2009
comment
Да, вы можете вернуться к узлу, если хотите!   -  person Alberto    schedule 17.07.2009
comment
Ах, это интересно. Тогда, я полагаю, Дейкстра сводится к поиску наилучших результатов. Похоже, поиск по первому наилучшему — моя последняя рекомендация.   -  person chaos    schedule 17.07.2009
comment
Да, но это то же самое, чтобы вычислить все возможные пути (в соответствии с правилом ввода).   -  person Alberto    schedule 17.07.2009
comment
Ты продолжаешь так говорить, но нет, это не так. Если ваши затраты на вершины на самом деле разные, есть много возможных путей, которые поиск наилучших результатов не будет вычислять, потому что их затраты выше.   -  person chaos    schedule 17.07.2009
comment
@chaos, посмотри мое обновленное изображение, он может выбрать любой путь к любому узлу, если он следует последовательности, то есть: после узла B любой узел C является честной игрой. Я думаю, что этот алгоритм может быть полезен: en.wikipedia.org/wiki/Kruskal%27s_algorithm< /а>   -  person Kent Fredric    schedule 17.07.2009
comment
no: kruskal строит минимальное остовное дерево для связного взвешенного графа.   -  person Alberto    schedule 17.07.2009
comment
да, для работы потребуется небольшая модификация, вы не можете использовать его дословно ... у вас должно быть какое-то правило проверки, которое решает, могут ли 2 края соприкасаться.   -  person Kent Fredric    schedule 17.07.2009
comment
ВСЕМ: прочитайте мой пример из жизни :-) Я добавил его в конце вопроса!   -  person Alberto    schedule 17.07.2009
comment
Верно. Поиск наилучших результатов пропускает огромное количество путей в этом примере, которые будут проверены поиском в ширину или полным поиском.   -  person chaos    schedule 17.07.2009


Ответы (8)


Вы можете использовать алгоритм Флойда-Уоршалла. Вот псевдокод, предоставленный WikiPedia:

/* Assume a function edgeCost(i,j) which returns the cost of the edge from i to 
   (infinity if there is none).
   Also assume that n is the number of vertices and edgeCost(i,i)=0
*/

int path[][];

/* A 2-dimensional matrix. At each step in the algorithm, path[i][j] is the shortest path
   from i to j using intermediate vertices (1..k-1).  Each path[i][j] is initialized to
   edgeCost(i,j) or infinity if there is no edge between i and j.
*/

procedure FloydWarshall ()
    for k: = 1 to n
        for each (i,j) in {1,..,n}2
            path[i][j] = min ( path[i][j], path[i][k]+path[k][j] );

Мне пришлось написать программу для курса алгоритмов по этой же проблеме. Этот алгоритм работал как шарм! Удачи.

person user140125    schedule 17.07.2009
comment
Алгоритм Дейкстры имеет лучшую сложность. - person niteria; 17.07.2009
comment
Я не понимаю, как вы хотите иметь дело с ограничением типа. - person niteria; 17.07.2009

Как упомянул Ян, вам просто нужен обычный скучный алгоритм кратчайшего пути (например, алгоритм Дейкстры или Флойда). алгоритм); однако вам необходимо преобразовать входной граф так, чтобы выходной путь соответствовал вашему ограничению пути.

Учитывая ограничение пути: A - B - A

Создайте новый граф G и вставьте все вершины из A в G с новыми метками, такими как a_01. Затем вставьте все вершины из B в G и соедините вершины A с вершинами B (ребра должны быть направлены в сторону вновь вставленных вершин), скопировав стоимости из исходного графа. Затем вы повторяете этот шаг с A (и любыми другими компонентами пути), соединяя вновь вставленные вершины с вершинами в B. Таким образом, вы создаете граф, в котором только существующие пути удовлетворяют ограничению пути. Затем вы можете использовать обычные алгоритмы кратчайшего пути.

Ключевым моментом является то, что когда вы повторно посещаете класс, вы на самом деле посещаете отдельный набор узлов и вам нужны только ребра, соединяющие соседние классы узлов.

person Aaron Maenpaa    schedule 17.07.2009
comment
@Alberto: это не то же самое, что вычисление всех возможных путей. Точно так же алгоритм Джикстры не вычисляет все возможные пути в обычной задаче поиска кратчайшего пути. Он находит лучший путь, не перебирая все возможные пути! Ответ Аарона правильный. Он и niteria (хотя код мне не нравится) правы. Остальные неверны или неясны. - person yairchu; 19.07.2009

Есть много алгоритмов, которые работают лучше, чем вычисление всех возможных путей. Поиск в ширину — основная отправная точка для семейства алгоритмов, которые я имею в виду. , Поиск по принципу "наилучшее в первую очередь" подходит, поскольку у вас определены затраты на вершины, и если вы можете чтобы получить больше информации о вашей проблемной области, вы можете использовать A* или алгоритм Дейкстры. (В каждом случае нахождение путей из множества разрешенных начальных узлов.)

Относительно вашего редактирования: ваше ограничение пути (массив типов узлов, которые вам необходимо удовлетворить) не мешает вам работать с этими алгоритмами; как раз наоборот, это помогает им всем работать лучше. Вам просто нужно реализовать их таким образом, чтобы можно было включить ограничение пути, ограничивая вершины, доступные на каждом шаге поиска, теми, которые допустимы с учетом ограничения.

person chaos    schedule 17.07.2009
comment
Если вы используете алгоритм Дейкстры, вы хотите иметь следующий кортеж в приоритетной очереди: (cost_so_far, current_vertex, number_of_vertices_visited). Затем при повторении исходящих ребер вы просто игнорируете ребра, которые приводят к нежелательным типам в соответствии с number_of_vertices_visited. - person niteria; 17.07.2009
comment
Я не могу использовать A* или Dijkstra. ЕСЛИ Я ИСПОЛЬЗУЮ BFS, ЭТО ЖЕ РАССЧИТАЕТ ВСЕ ПУТИ! - person Alberto; 17.07.2009
comment
Можно, если последуешь совету. - person niteria; 17.07.2009
comment
Поиск наилучшего первого — это не то же самое, что вычисление всех путей, потому что он преимущественно исследует те, у которых более низкая стоимость вершин. - person chaos; 17.07.2009
comment
В ответ на мое редактирование: я не уверен, что понял, что вы сказали... могу я это сделать? - person Alberto; 17.07.2009
comment
Как минимум, вы можете использовать поиск по первому наилучшему, да. Я считаю, что вы правы, что вы не можете использовать A *. Я недостаточно опытен с Дейкстрой, чтобы сказать с полной уверенностью, но мне кажется, что вы можете, и Нитерия, похоже, уверена в этом. - person chaos; 17.07.2009
comment
Если вы можете вернуться к узлам, я не уверен, что Дейкстра все еще работает. Тогда динамическое программирование — это путь. - person niteria; 17.07.2009
comment
Синхронизация с комментариями к вопросу, так как вы можете вернуться, алгоритм Дейкстры также отсутствует, так что остается поиск по первому наилучшему. Что, опять же, намного лучше, чем вычисление всех путей. - person chaos; 17.07.2009
comment
это не лучше, это точно так же - person Alberto; 17.07.2009
comment
Эм. Хорошо. Я предполагаю, что вы используете вычисление всех путей специальным образом, что на самом деле означает выполнение поиска по первому наилучшему. Потому что обычно вычисление всех путей означает исчерпывающий поиск, который является огромным улучшением по сравнению с поиском по первому наилучшему. - person chaos; 17.07.2009
comment
И действительно, если поиск по принципу поиска наилучших вычисляет все пути, то что такое поиск в ширину? Расчет больше, чем все пути? - person chaos; 17.07.2009

альтернативный текст

Вот как я сейчас интерпретирую вашу проблему.

Красные стрелки показывают, что я вручную отслеживаю пути, которые соответствуют заданному ограничению порядка.

Стоимость не указана, но предполагается, что все ссылки несут затраты, а стоимость ссылок различна.

Если это точно описывает сценарий, который вы пытаетесь решить, укажите это, чтобы другие могли лучше ответить на вопрос.

person Kent Fredric    schedule 17.07.2009
comment
Однако я не думаю, что у него есть начальный узел, как вы изображаете; скорее, если его ограничение пути начинается с A, он начинает с набора узлов A. - person chaos; 17.07.2009
comment
очень похоже, НО если правило A-B-C, я должен связать точку A-типа с B-типом и C-типом и СТОП!!!! - person Alberto; 17.07.2009
comment
о, я говорил с ... Это был повтор ABC :) - person Kent Fredric; 17.07.2009
comment
теперь ты очень-очень близко. НО КАК Я НАПИСАЛ В ВОПРОСЕ: у меня есть n точек (p1,p2,p3,..pn), каждая из них может соединяться с любыми другими - person Alberto; 17.07.2009
comment
Э-э, технически, потому что невозможно добраться до этих узлов, соблюдая правило соединения. IE: по моему правилу вы не можете перейти из C в B, поэтому эти узлы ЯВЛЯЮТСЯ недостижимыми. - person Kent Fredric; 17.07.2009
comment
Хорошо, но узел A в правом нижнем углу может соединиться с узлом B в левом среднем углу, который может соединиться с узлом C в левом верхнем углу. Итак... нет недостижимых узлов. Я даю вам голосование! - person Alberto; 17.07.2009
comment
Я обновил изображение, чтобы лучше представить односторонние соединения между всеми узлами, посмотрите, что вы думаете. - person Kent Fredric; 17.07.2009

При пересмотре вашего вопроса кажется, что вы запрашиваете один узел на букву - в этом случае это простое решение динамического программирования: вычислите все кратчайшие пути длины 1, которые удовлетворяют началу вашей последовательности, между каждой парой узлов. Тогда, имея для k все такие пути для всех пар узлов, построить для k+1 несложно.

person EFraim    schedule 17.07.2009
comment
... но по-умному. Вы повторно используете результаты своих предыдущих вычислений. - person niteria; 17.07.2009

Вот псевдокод с решением для динамического программирования:

n - length of desired path
m - number of vertices
types[n] // desired type of ith node
vertice_types[m]
d[n][m] // our DP tab initially filled with infinities

d[0][0..m] = 0
for length from 1 to n 
  for b from 0 to m
    if types[length] == vertice_types[b]
      for a from 0 to m
        if types[length-1] == vertice_types[a]
          d[length][b] = min(d[length][b], d[length-1][a] + cost(a,b))

ваш путь с минимальной стоимостью min(d[n][0..m])

вы можете уменьшить размер таблицы d до 2 строк, но это запутает решение

person niteria    schedule 17.07.2009
comment
imho, гораздо лучше сделать свой псевдокод в стиле python, то есть - без endif/endfor шума: отступы имеют значение. поздравляю с правильным решением. - person yairchu; 19.07.2009

Насколько я понимаю ваш вопрос, вам нужен кратчайший путь в ориентированном графе. http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm должен дать вам идея.

С уважением, Ян

person Community    schedule 17.07.2009
comment
нет, спасибо за ответ, но это другое! Пожалуйста, прочитайте мой (отредактированный) вопрос лучше. - person Alberto; 17.07.2009

  1. Вычислите все пары кратчайших путей в каждом блоке эквивалентности.
  2. Теперь постройте граф, в котором НЕТ межклассовых ребер, но чьи ребра между классами соответствуют кратчайшему пути внутри этого класса, ведущему к определенному узлу другого класса.

Надеюсь, это понятно.

Это решение не особенно эффективно, но явно полиномиально.

person EFraim    schedule 17.07.2009