Куди йде та змія?


35

Напишіть функцію (використовуючи якомога менше байтів), яка займає двовимірний масив будь-якої кількості стовпців і рядків, у якій:

  • 0 являє собою порожній блок,
  • 1 являє собою зміїний блок.

Функція повинна повертати кількість можливих шляхів, якими пройшла змія.

Приклад 1:

Вхід:

[
  [1,1,1,1,1],
  [0,0,0,0,1],
  [0,0,0,0,1],
]

Вихід: 2

У наведеному вище прикладі функція повернеться, 2тому що відповідь є одним із:

введіть тут опис зображення

Приклад 2:

Вхід:

[
  [1,1,1,1],
  [0,0,1,1],
  [0,0,1,1],
]

Вихід: 6

У цьому прикладі функція повернеться, 6тому що відповідь є одним із:

введіть тут опис зображення

Примітка:

Оцінюючи вхід, ви можете припустити, що:

  • Масиви, що представляють стовпці, завжди матимуть однакові розміри (тому масиви прямокутні);
  • Існує щонайменше 1 дійсний шлях;
  • Змія не може ходити по краях (як це може статися в деяких версіях змії);
  • Змія завжди матиме як мінімум 2 блоки;
  • Змія не може рухатися по діагоналі;
  • Шляхи спрямовані. (так, два контури, що закінчуються на різних позиціях, але в іншому випадку виглядають абсолютно однаково, не є однаковим шляхом, він додасть до загальної кількості)

13
Ласкаво просимо до PPCG! Гарний перший виклик.
Лайконі

5
Незначна примітка: "Завжди буде хоча б один рядок і один стовпець" зайве, враховуючи, що змія завжди матиме принаймні 2 блоки.
Стюі Гріффін

2
Пропоновані тестові випадки: той, який подав @StewieGriffin та [[0,0,1,1],[0,0,1,1],[0,0,1,1]]. Більшість відповідей дають 16, але одна дає 15.
Кевін Круїссен

2
Схоже, всі поки що (включаючи мене) зробили припущення, що 2 шляху, що закінчуються на різних положеннях, але в іншому випадку виглядають абсолютно однаково, не є однаковою стежкою. Я думаю, що це потрібно чітко вказати.
Арнольд

2
@Arnauld - саме так. Два контури, що закінчуються на різних позиціях, але в іншому випадку виглядають абсолютно однаково , не є одним і тим же шляхом , це додасть до загальної кількості. У вашому прикладі загальна сума повинна становити 16, якщо я не помиляюсь - я не можу точно розрахувати зараз, але ви отримаєте бал
Аделін

Відповіді:


11

Мова Вольфрама (Mathematica) , 16 + 83 = 99 байт

Заява про імпорт бібліотеки (16 байт):

<<Combinatorica`

Тіло фактичної функції (83 байти):

Length@HamiltonianCycle[MakeGraph[#~Position~1~Join~{1>0},##||Norm[#-#2]==1&],All]&

Спробуйте в Інтернеті!


Зауважте, що питання просто задає кількість гамільтонівського шляху в графі.

Однак HamiltonianPathфункція (чомусь) насправді не працює з спрямованим графіком ( приклад ). Отже, я використав рішення, описане в цьому питанні Mathematica.SE :

  • Додайте вершину (називається True), яка з'єднана з усіма іншими вершинами.
  • Порахуйте кількість гамільтонівського циклу на отриманому графіку.

Графік побудований за допомогою MakeGraph(дратівливо немає вбудованого прямо еквівалентного), використовуючи булева функція ##||Norm[#-#2]==1&, яка повертається Trueтоді і лише тоді, коли один з аргументів є Trueабо відстань між двома вершинами 1.


Tr[1^x]не може бути використаний замість Length@x, і <2не може бути використаний замість ==1.


HamiltonianPathможе використовуватися, якщо графік непрямий, при цьому функціональне тіло займає 84 байти (рівно на 1 байт більше, ніж поточне подання):

Length@HamiltonianPath[MakeGraph[#~Position~1,Norm[#-#2]==1&,Type->Undirected],All]&

Спробуйте в Інтернеті!


10

JavaScript (ES6), 154 134 байт

m=>m.map((r,Y)=>r.map(g=(_,x,y,r=m[y=1/y?y:Y])=>r&&r[x]&&[-1,0,1,2].map(d=>r[r[x]=0,/1/.test(m)?g(_,x+d%2,y+~-d%2):++n,x]=1)),n=0)|n/4

Спробуйте в Інтернеті!

Як?

Метод

Починаючи з кожної можливої ​​комірки, ми заливаємо матрицю, очищаючи всі комірки на своєму шляху. Щоразу, коли матриця не містить більше 1 -х, ми збільшуємо число n можливих шляхів.

Кожен дійсний шлях обчислюється 4 рази через напрямок, обраний на останній комірці, що насправді не має значення. Отже, кінцевий результат - n / 4 .

Рекурсивна функція

Замість виклику рекурсивної функції g () з зворотного виклику другої карти (), як це ...

m=>m.map((r,y)=>r.map((_,x)=>(g=(x,y,r=m[y])=>...g(x+dx,y+dy)...)(x,y)))

... ми визначимо рекурсивную функцію г () безпосередньо в якості зворотного виклику з карти () :

m=>m.map((r,Y)=>r.map(g=(_,x,y,r=m[y=1/y?y:Y])=>...g(_,x+dx,y+dy)...))

Незважаючи на досить довгу формулу y=1/y?y:Y, необхідну для встановлення початкового значення y , це економить 2 байти в цілому.

Коментований код

m =>                           // given the input matrix m[][]
  m.map((r, Y) =>              // for each row r[] at position Y in m[][]:
    r.map(g = (                //   for each entry in r[], use g() taking:
      _,                       //     - the value of the cell (ignored)
      x,                       //     - the x coord. of this cell
      y,                       //     - either the y coord. or an array (1st iteration),
                               //       in which case we'll set y to Y instead
      r = m[y = 1 / y ? y : Y] //     - r = the row we're currently located in
    ) =>                       //       (and update y if necessary)
      r && r[x] &&             //     do nothing if this cell doesn't exist or is 0
      [-1, 0, 1, 2].map(d =>   //     otherwise, for each direction d,
        r[                     //     with -1 = West, 0 = North, 1 = East, 2 = South:
          r[x] = 0,            //       clear the current cell
          /1/.test(m) ?        //       if the matrix still contains at least one '1':
            g(                 //         do a recursive call to g() with:
              _,               //           a dummy first parameter (ignored)
              x + d % 2,       //           the new value of x
              y + ~-d % 2      //           the new value of y
            )                  //         end of recursive call
          :                    //       else (we've found a valid path):
            ++n,               //         increment n
          x                    //       \_ either way,
        ] = 1                  //       /  do r[x] = 1 to restore the current cell to 1
      )                        //     end of map() over directions
    ),                         //   end of map() over the cells of the current row
    n = 0                      //   start with n = 0
  ) | n / 4                    // end of map() over the rows; return n / 4

10

Желе , 12 11 байт

ŒṪŒ!ạƝ€§ÐṂL

Спробуйте в Інтернеті!


Пояснення.

ŒṪ               Positions of snake blocks.
  Œ!             All permutations.
                 For each permutation:
    ạƝ€             Calculate the absolute difference for each neighbor pair
       §            Vectorized sum.
                 Now we have a list of Manhattan distance between snake
                    blocks. Each one is at least 1.
        ÐṂL      Count the number of minimum values.
                    Because it's guaranteed that there exists a valid snake,
                    the minimum value is [1,1,1,...,1].

Нові функції виявляються надзвичайно корисними.
користувач202729

Як щодо §ỊMLзамість того, §ỊP€Sщоб зберегти байт - я думаю, він повинен працювати?
Джонатан Аллан

... або §ÐṂLщо трохи швидше.
Джонатан Аллан

@JonathanAllan Працює, лише якщо результат не нульовий.
користувач202729

@JonathanAllan Таким чином, це в кінцевому підсумку працює.
користувач202729

8

Python 2 , 257 246 241 234 233 227 214 210 байт

lambda b:sum(g(b,i,j)for j,l in e(b)for i,_ in e(l))
e=enumerate
def g(b,x,y):d=len(b[0])>x>-1<y<len(b);c=eval(`b`);c[d*y][d*x]=0;return d and b[y][x]and('1'not in`c`or sum(g(c,x+a,y)+g(c,x,y+a)for a in(1,-1)))

Спробуйте в Інтернеті!


Збережено

  • -8 байт, завдяки Кевіну Крейсейну
  • -14 байт, завдяки користувачу202729


1
Правильна мова для роботи?
Ніл


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.