Обход графа C # - отслеживание пути между любыми двумя узлами - PullRequest
3 голосов
/ 11 сентября 2008

В поисках хорошего подхода для отслеживания обхода в ширину между двумя узлами, ничего не зная о графике. По сравнению с глубиной-первой (где вы можете выбросить путь, если он не работает) у вас может быть довольно много «открытых» возможностей во время обхода.

Ответы [ 4 ]

2 голосов
/ 12 сентября 2008

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

1 голос
/ 12 сентября 2008

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

По сути, я просто держу один список (действительно, стек) посещенных узлов. Добавьте узел в список непосредственно перед повторением или сохранением решения. Всегда удалять из списка сразу после.

1 голос
/ 12 сентября 2008

Для поиска в ширину вам нужно хранить как минимум две вещи. Один - это набор уже посещенных узлов, а другой - набор узлов, к которым можно напрямую добраться из посещенных узлов, но которые сами не посещаются. Затем вы продолжаете перемещать состояния из последнего набора в первый, добавляя недавно достижимые состояния ко второму. Если вам нужен путь от корня до какого-либо узла (ов), вам также необходимо сохранить родительский узел для каждого узла (кроме корня) в вышеупомянутых наборах.

Обычно объединение набора посещенных узлов и набора непосещенных дочерних узлов (то есть набора видимых узлов) сохраняется в хэш-таблице. Это должно быть в состоянии быстро определить, было ли «новое» состояние замечено ранее, и игнорировать его, если это так. Если у вас действительно большое количество состояний, вам действительно может понадобиться битовый массив (как упомянул Джозеф Буй ( 57509 )), но если ваши состояния не могут использоваться (прямо или косвенно) в качестве индексов для этого массива, вы потребуется использовать хеш-функцию для сопоставления состояний с индексами. В последнем случае вы можете полностью игнорировать определенные состояния, потому что они отображаются на тот же индекс, что и другой (и видимый) узел, поэтому вы можете быть осторожны с этим. Кроме того, чтобы получить путь, вам все равно нужно хранить родительскую информацию, которая в значительной степени сводит на нет использование битового массива.

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

0 голосов
/ 04 октября 2008

Если вы используете .NET 3.5, рассмотрите возможность использования Hashset для предотвращения расширения дублирующих узлов, это происходит, когда в вашем графике есть циклы. Если у вас есть какие-либо знания о содержимом графа, подумайте о реализации поиска A * , чтобы уменьшить количество развертываемых узлов. Удачи, и я надеюсь, что это сработает для вас.

Если вы все еще являетесь поклонником Treeware, есть много превосходных книг на тему графиков и поиска графиков, таких как «Искусственный интеллект: современный подход» Питера Норвига и Стюарта Рассела.

Похоже, что ссылки в моем ответе содержат ошибку Hashset: http://msdn.com/en-us/library/bb359438.aspx и A * search: http://en.wikipedia.org/wiki/A*_search_algorithm

...