Насколько разнообразна моя полоса препятствий?


21

Задний план

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

вход

Ваш ввод представляет собой непустой прямоугольный массив символов .#. Точки .- это пустое пространство, и они #являются препятствиями.

Путь через препятствие курс начинается в верхнем левом углу и заканчивается в правом нижнем углу, и идет только вправо или вниз. Кроме того, действительный путь не может пройти через препятствие. Вот несколько примеров, нарисованных с помощью +символов -characters:

Valid path  Invalid path  Invalid path  Invalid path
++........   ++........    +++++.....    ..+.......
.++++++#..   .+.....#..    ....+++#++    ..++...#..
......+#..   .+.++++#..    .......#.+    ...+++.#..
....#.++++   .+++#.++++    ....#....+    ....#+....

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

++........   +.........   +++++++++.
.+++++.#..   ++.....#..   .......#+.
.....+.#..   .++++++#..   .......#++
....#+++++   ....#.++++   ....#....+

Выход

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

Правила и оценки

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

Контрольные примеры

....
....
.... => 1

...#
....
...# => 0

#..#
..#.
.... => 0

......
......
..##..
......
...... => 2

......
...#..
......
..#...
#..... => 3

......
..#...
......
....#.
#..... => 4

.......
##.....
....###
...#...
..##.#.
#....#.
..#.... => 0

......#.
..##....
...#....
.......#
....#...
.##...#.
....#...
##...... => 7

.........
.#.#.#.#.
.........
#.#...#.#
.........
.#.#.#.#.
......... => 17

..........
.#........
..........
.....#....
#.........
........#.
......#...
.......... => 10

.........
.#.......
.........
...#.....
.........
.....#...
.........
.......#.
......... => 16

1 Правильный технический термин - «гомотопный» .


1
Что вы имеете в виду под « движется один +в то время »? Означает ли это, что по существу одинаковые пути должны быть одинаковой длины?
Питер Тейлор

3
@PeterTaylor Все пути имеют одинаковую длину, так как они могут идти только вниз и вправо. Под «движением одного +» я, по сути, имею в виду, что один угол пути инвертирован в угол противоположного направления.
Згарб

1
@Peter: Поскольку вы можете идти только вправо или вниз, все пути имеют одинаковую длину.
Деусови

Ответы:


8

Улитки , 53 49 байт

A^
\.+d!{.l\.+a3(.|~c!~}\.+r!(.u\.+e(.|~},\.,=~d~

На этот раз мне не пришлось пользоваться tстрашной инструкцией телепорта. В результате тестовые случаи заканчиваются мгновенно, вместо того, чтобы брать эоны.

Ungolfed:

A^
r\.+
{
    d\.+
    !{ r\.u \.+ a3 (.|~)}
    r\.+
    !{ d\.l \.+ a3 (.|~)}
},
d\.,
!(dr .)

Параметры A^означают, чтобы начать в верхнем левом углу и подсчитать все соответствующие пути. Основная идея состоит в том, чтобы проверить условие каноничности для путей. Я, честно говоря, не ожидал, что это сработает, но он прибил контрольные тесты, так что ... То, что он пытается проверить, - это то, что в текущем пути выбран самый жадный маршрут, то есть идет столько раз, сколько возможно вниз столько раз, сколько это возможно, и т.д., не пересекая любые препятствия. Это делается путем проверки, после перемещения вправо 1 или более раз, а затем вниз 1 или более раз, что следующий квадрат (который должен быть справа) не может быть достигнут, пройдя еще раз вправо в предыдущем правом сегменте. Аналогичное условие также проверяется после перемещения вправо, а затем вниз.


говорить о правильном языке для работы!
Не то, что Чарльз

10

Python 2, 170 131 112 байт

def f(C,t=1):i="#".join(C).find("#")+1;return([]<C)*(i<1or(i<t
and f([r[i:]for r in C],t-i))+(i>1)*f(C[1:],i-1))

Функция, fпринимающая полосу препятствий в виде списка строк и возвращающая количество принципиально разных путей.

объяснение

Основная концепция такова: мы выбираем определенное препятствие o , чтобы в прямоугольнике, ограничивающем о и верхний левый угол , не было других препятствий .

+--+....
|..|....  
+--#<==== o
.....#..
.#......
........

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

                               A
_
........       ...|////      |....
........       ...|////      |....
...#....  -->  ...#////  -->  ....
.#....#.       .#..//#/       ..#.
........       ....////       ....

   |                           |
   v                           v
                  B
........       ___
........       .#....#.
___#....  -->  ........  -->   +
/#////#/       
////////       

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

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

Фактический выбор o выглядит следующим образом: мы делаем вид, что за каждой строкой, отличной от последней, следует препятствие (т. #Е. К нему добавлено), и выбираем первое препятствие в результирующем курсе в порядке чтения. Для строк (кроме последней), в которых изначально не было препятствий, это фактически означает, что мы их пропускаем (при этом отмечается, что путь ниже может начинаться с любого символа в верхней строке). В итоге мы получаем курс, в котором есть один ряд без препятствий, для которого существует только один возможный путь.


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

6

CJam, 85 84 82 81 80 79 байтов

qN/:Q,(Qz,(:R_T]2/e~e!{'#Qs@{\(\@>}%s-},{_}{(a\L{@+_@\-_{2$\f.=0fe=2&},}h;}w;],

Попробуйте онлайн. Или запустить весь набор тестов.

Эффективность этого решения, вероятно, довольно ужасна, но она решает каждый тестовый случай в течение нескольких секунд.

объяснение

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

  • Пусть ширина и высота сетки будут Wи Hсоответственно.
  • Мы генерируем все возможные пути как отдельные перестановки W-1копий 0и H-1копий W-1(где 0представляет горизонтальный шаг и W-1вертикальный шаг). Мы проходим все эти пути, многократно беря первый элемент сетки, а затем пропуская stepячейки в порядке чтения (где stepесть 0или W-1). Мы отбрасываем все пути, которые содержат #.
  • Затем мы неоднократно удаляем одну группу похожих путей (которые будут всеми путями, похожими на первый из оставшихся путей). Проверка на похожие пути становится немного проще, если немного ослабить условие для них: вместо того, чтобы проверить, xпереместился ли один , мы проверяем, отличаются ли пути ровно в двух местах. Если это так, то в этих двух местах вертикальное и горизонтальное движение поменяются местами. Это приводит к тому, что весь сегмент между этими движениями смещается по диагонали на одну ячейку. Но если оба этих пути верны, смещение любой части пути на одну ячейку по диагонали не может пересечь препятствие, поэтому они похожи. Нам все еще нужно найти транзитивное замыкание, поэтому мы продолжаем делать это до тех пор, пока не найдем больше похожих путей, прежде чем перейти к следующей группе.
  • Наконец, мы подсчитываем найденные группы, которые мы оставили в нижней части стека.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.