2012-04-01 3 views
2

Рассмотрите эту проблему:Проверка проходимости сетки

Существует квадратная сетка, каждая из которых является проходной (1) или непроходимой (0). Во-первых, мы имеем просто связное пространство в сетке с непроходимой границы, как это:

enter image description here

Затем начать размещение непреодолимые препятствия различных размеров (например, 1х1, 2х2, ..) в проходимое пространство. После того, как каждое препятствие помещено, нам нужно проверить, все ли еще подключено оставшееся проходимое пространство (т. Е. Убедитесь, что мы не разделили проходимое пространство в двух или более отключенных пространствах). Плитки также соединены по диагонали.

Дело в том, что после каждого размещения препятствий каждая оставшаяся проходимая плитка имеет путь, соединяющий ее с КАЖДОЙ другой оставшейся проходимой плиткой.

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

Спасибо за помощь!

ответ

4

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

+0

_Seems legit._ :) Спасибо! – vedran

1

Wikipedia says что это можно сделать в амортизированном времени O (| V |) с использованием структур данных с несвязанными наборами, где V - количество элементов в проходимом пространстве (второй абзац этого раздела). Цитируется в this paper.

Это та же самая асимптотическая сложность, что и Benjamin's answer, и ее, по-видимому, сложнее реализовать, поэтому я бы пошел с этим. :)

+2

Это решение подходит, когда вы * добавляете * вершины, а не * удаляете их. Однако, если его можно каким-то образом использовать для удаления ребер, это будет намного более эффективно, чем 'O (| V |)'. У вас будет предварительная обработка 'O (| V |)' в первый раз, но для каждого добавленного препятствия она будет намного быстрее, чем 'O (| V |)'. Это будет 'O (alpha (n))' где 'alpha' является обратной функцией [ackerman] (http://en.wikipedia.org/wiki/Ackermann_function), которая меньше 4 для каждого практического ввода. Но я не уверен, что вы можете использовать его для удаления краев. – amit

+0

Хорошая мысль, я читал небрежно. Я действительно не знаю, есть ли способ использовать union-find (с его версией обратного-Ackermann) для удаления ребер .... для этого потребуется какой-то трюк, например, построение двойного графика (не то, что не Работа). – Dougal