Наскільки різний мій перешкод?


21

Фон

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

Вхідні дані

Ваш вхід - це порожній прямокутний масив символів .#. Крапки - .це порожній простір, а #перешкоди.

Шлях через перешкоду курс починається у верхньому лівому кутку і закінчується в правому нижньому кутку, і йде тільки вправо або вниз. Також дійсний шлях не може пройти через перешкоду. Ось кілька прикладів, намальованих за допомогою +-символів:

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: Оскільки ви можете рухатись лише вправо або вниз, усі контури однакової довжини.
Deusovi

Відповіді:


8

Равлики , 53 49 байт

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

Одного разу мені не довелося користуватися t, жахливою інструкцією щодо телепорту. В результаті тестові справи закінчуються миттєво, замість того, щоб приймати еони.

Безголівки:

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

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


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

10

Пітон 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 насправді можна перетнути з напрямку, що веде до них, тобто перетнути з півночі, щоб дістатися до сходу, і перетнути з заходу, щоб дістатися до півдня. Ми вирішуємо задачу для кожного з обраних підкурсів і повертаємо суму результатів. Ці числа відповідають кількості по суті різних шляхів при перетині o зліва і справа відповідно, тому два результуючі набори шляхів істотно відрізняються. Оскільки між початковою точкою та o немає перешкод, існує шлях між початковою точкою та будь-якою точкою входу до кожної з цих областей, і всі такі шляхи, які ведуть до тієї ж точки, по суті схожі, отже, вищевказана сума є повною кількістю по суті різних шляхів у всьому ході.

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

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

Речі дещо ускладнюються тим фактом, що сам курс перешкод не передає всієї необхідної інформації. Наприклад, розгляньте курс В на схемі вище. Взявшись самостійно, ми не можемо визначити, чи можна перетинати кожну із перешкод із півночі. Якби B був вхідним ходом, то, оскільки всі шляхи починаються у верхньому лівому куті, жодна перешкода не могла бути перетнута з півночі, але, оскільки ми можемо досягти B з будь-якого боку лівої перешкоди при перетині o зі сходу ми повинні ставитися до цієї перешкоди так, ніби вона може перетинатися з півночі при вирішенні курсу; те саме не відповідає правильній перешкоді, яку неможливо перетнути з цього напрямку.

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

Фактичний вибір o такий: Ми робимо вигляд, що за кожним рядком, окрім останнього, йде перешкода (тобто #додається до нього), і вибираємо першу перешкоду в отриманому курсі в порядку читання. Для рядків (крім останніх), які не мали перешкод спочатку, це фактично означає, що ми їх пропускаємо (зазначаючи, що шлях внизу може починатися з будь-якого символу в верхньому ряду). Врешті-решт ми закінчуємо курс, який має єдиний ряд без перешкод, для якого існує лише один можливий шлях.


це майже рішення, яке я розглядав. Я знав, що хтось опублікує це, перш ніж я отримав шанс.
Кінтопія

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). Ми відкидаємо всі шляхи, які містять a #.
  • Потім ми неодноразово видаляємо одну групу подібних контурів (які будуть усіма шляхами, схожими на перший із решти шляхів, що залишилися). Перевірка подібних шляхів стає трохи простішою, трохи послабивши для них умову: замість того, щоб перевірити, чи xрухався один , ми перевіряємо, чи відрізняються шляхи рівно в двох місцях. Якщо це так, у цих двох місцях буде змінено вертикальний та горизонтальний хід. Це призводить до того, що весь сегмент між цими рухами зміщується по діагоналі на одну клітинку. Але якщо обидва ці шляху є дійсними, переміщення будь-якої частини шляху на одну клітинку по діагоналі не може перетнути перешкоду, тому вони схожі. Нам ще потрібно знайти перехідне закриття, тому ми продовжуємо це робити, поки не знайдемо більше подібних шляхів, перш ніж перейти до наступної групи.
  • Нарешті, ми підраховуємо знайдені нами групи, які ми залишили внизу стеку.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.