Розбиття сітки на трикутники


18

Мета

Мета цього завдання - створити функцію, nяка обчислює кількість способів розділити n X 1сітку на трикутники, де всі вершини трикутників знаходяться в точках сітки.

Приклад

Наприклад, існує 14 способів розділити сітку 2 х 1, тому f(2) = 14через наступні розділи, Перегородки 2 х 1 де перегородки мають 2, 2, 2, 2, 4 та 2 різних орієнтації відповідно.

Оцінка балів

Це , тому найкоротший код виграє.


10
Деякі додаткові тестові випадки будуть корисними, тому ми можемо перевірити правильність наших даних.
AdmBorkBork

8
Ви можете вказати неперероджені трикутники.
Арнольд

1
Я змінив послідовність OEIS A051708, щоб відобразити цю інтерпретацію.
Петро Кагей

Відповіді:


2

05AB1E , 13 байт

·LÉœÙεÅγo;P}O

Порт @Bubbler Jelly відповіді «s .

Дуже повільно через вбудовані перестановки.

Спробуйте в Інтернеті або перевірте перші чотири входи .

Пояснення:

·                # Double the (implicit) input
 L               # Create a list in the range [1, doubled_input]
  É              # Check for each if they're odd (1 if truthy, 0 is falsey)
                 # We now have a list of n 0s and n 1s (n being the input)
   œ             # Get all permutations of that list
    Ù            # Only leave the unique permutations
     ε     }     # Map each permutation to:
      Åγ         #  Run-length encode the current value (short for `γ€g`)
        o        #  Take 2 to the power for each
         ;       #  Halve each
          P      #  Take the product of the mapped permutation
            O    # Sum all mapped values together (and output implicitly)

19

Haskell , 60 55 54 52 байт

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

На шаховій дошці скільки способів, щоб грак перейшов з до , просто перемістившись вправо або вгору ?(n+1)×(n+1)(0,0)(n,n)+(1,0)+(0,1)

В основному у вас є верхня і нижня лінія сітки . Тепер ви повинні заповнити не горизонтальну лінію. Кожен трикутник повинен мати дві не горизонтальні лінії. Незалежно від того, що одна з її сторін є частиною верхньої чи нижньої лінії, відповідає напрямку та довжині, яку ви хочете вирішити в проблемі граків. Це OEIS A051708 . В якості ілюстрації цього листування розглянемо наступні приклади. Тут верхній рядок відповідає вгору, а нижній - правому.1×н

Дякую @PeterTaylor за -6 байт та @PostLeftGarfHunter за -2 байти!

b 0=1
b 1=2
b n=div((10*n-6)*b(n-1)-9*(n-2)*b(n-2))n

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


Я знайшов послідовність OEIS шляхом пошуку за першими кількома значеннями. Приємне пояснення того, чому воно відповідає. Ви хочете відредагувати його, щоб додати коментар до цієї альтернативної комбінаторної інтерпретації? Якщо ні, то, можливо.
Пітер Тейлор

До речі, вам потрібно скорегувати індексацію, оскільки правильна відповідь тут A051708(n+1). Тож я опублікував першу правильну відповідь :-P
Пітер Тейлор

Я вважаю, що карта шару переміщається на трикутники, роблячи трикутники з верхніми та нижніми краями вгору чи вправо?
Ніл

@PeterTaylor Блін, спасибі за вказівку на мою помилку :)
flawr

5
@Neil Я додав графічне пояснення.
недолік

8

Хаскелл , 42 байти

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

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

Досить пряма реалізація, яка повторюється понад 2 змінних.

Ось як ми можемо отримати це рішення. Почніть з коду, що реалізує пряму рекурсивну формулу:

54 байти

0%0=1
a%b=sum$map(a%)[0..b-1]++map(b%)[0..a-1]
f n=n%n

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

Використовуючи інтерпретацію переміщення ладу flawr , a%b- це кількість шляхів, які отримують грак (a,b)до (0,0), використовуючи лише переміщення координати зменшення. Перший хід або зменшується, aабо зменшується b, зберігаючи другий таким же, звідси і рекурсивна формула.

49 байт

a?b=sum$map(a%)[0..b-1]
0%0=1
a%b=a?b+b?a
f n=n%n

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

Ми можемо уникнути повторення map(a%)[0..b-1]++map(b%)[0..a-1], зазначивши, що дві половинки однакові aі bзамінені. Допоміжний виклик a?bпідраховує шляхи, де зменшується перший хід a, і так b?aрахує ті, де зменшується перший хід b. Вони взагалі різні, і вони додають a%b.

Підсумок у a?bтакож може бути записаний як розуміння списку a?b=sum[a%i|i<-[0..b-1]].

42 байти

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

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

Нарешті, ми позбутися %і просто написати рекурсию з точки зору ?шляхом заміни a%iз a?i+i?aв рекурсивном виклик.

Новий базовий випадок призводить ?до того, що виходи вдвічі перевищують показники ?у 49-байтовій версії, оскільки у 0?0=1нас це буде 0%0=0?0+0?0=2. Це дозволяє використовувати визначення f n=n?nбез навпіл, що нам потрібно було б зробити.


Ваше 49-байтне рішення використовує ту саму рекурсію, що і моя відповідь, але 42-байтну я ще не з'ясував. Пояснення було б добре.
Пітер Тейлор

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

Оператор a%bпідраховує кількість розділів, використовуючи вузли 0,1,...,aу верхньому рядку, і ківки 0,1,..,bв нижньому рядку. Оператор a?bпідраховує кількість способів додавання нового рядка з верхнього вузла, aякщо нижній вузол bвже використовується. (Ви можете підключитися aдо всіх вузлів [0,1,...,b-1], але тоді вам доведеться повторити для кожного з них.)
flawr

@flawr, це 49-байтний, який я розумію. Це ?42-байтовий той, який я ні, і що особливо цікаво, це те, що він не симетричний.
Пітер Тейлор

@PeterTaylor Вибачте за плутанину, я якось переплутав два рішення. Я думаю, що ми можемо досить легко перетворити два рішення в інші: На першому кроці ми можемо замінити map...розуміння списку, на другому кроці ми просто підключимо визначення %:a?b=sum$map(a%)[0..b-1], a%b=a?b+b?a a?b=sum[a%i|i<-[0..b-1]], a%b=a?b+b?a a?b=sum[a?i+i?a|i<-[0..b-1]]
flawr

7

CJam (24 байти)

{2,*e!{e`0f=:(1b2\#}%1b}

Демонстрація в Інтернеті

Для цього використовується підхід Bubbler для підсумовування перестановок n0s і n1s.

Розсічення

{         e# Define a block
  2,*     e#   Given input n, create an array of n 0s and n 1s
  e!      e#   Generate all permutations of that array
  {       e#   Map:
    e`    e#     Run-length encode
    0f=:( e#     Extract just the lengths and decrement them
    1b    e#     Sum
    2\#   e#     Raise 2 to the power of that sum
  }%
  1b      e#  Sum the mapped values
}

Альтернативний підхід (28 байт)

{_1aa{_2$,f{j}@@,f{j}+1b}2j}

Демонстрація в Інтернеті

Розсічення

Усі трикутники мають один горизонтальний край і два ребра, які з'єднують горизонтальні лінії. Позначте негоризонтальні ребра за допомогою куточка їх двох x-координат і відсортуйте лексикографічно. Тоді перший край є (0,0), останній край є (n,n), а два послідовних ребра відрізняються точно в одному з двох положень. Це спричинить просту рекурсію, яку я реалізував, використовуючи запам'ятований оператор рекурсії j:

{            e# Define a block
  _          e#   Duplicate the argument to get n n
  1aa        e#   Base case for recursion: 0 0 => 1
  {          e#   Recursive body taking args a b
    _2$,f{j} e#     Recurse on 0 b up to a-1 b
    @@,f{j}  e#     Recurse on a 0 up to a b-1
    +1b      e#     Combine and sum
  }2j        e#   Memoised recursion with 2 args
}

Примітка

Це не перший раз, коли я хотів fjотримати підтримку в CJam. Тут це також знизить бал до 24 байт. Можливо, я повинен спробувати написати патч ...


Так, я побив тебе за 10 секунд, я не думаю, що я коли-небудь був таким близьким :)
недолік

@flawr, я думав над публікацією перед тим, як писати розсічення, але думав, що встигну швидко вибити його. Тоді я побачив "Нову відповідь", тому я видалив свою частково написану дисекцію, розмістив та відредагував.
Пітер Тейлор

1
Дякую за -5 байт btw: D
flawr

4

Желе , 15 14 байт

Ø.xŒ!QŒɠ€’§2*S

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

-1 байт на основі коментаря Пітера Тейлора.

Використовує ілюстрацію flawr безпосередньо замість отриманої формули.

Як це працює

Ø.xŒ!QŒɠ€’§2*S    Main link (monad). Input: positive integer N.
Ø.x               Make an array containing N zeros and ones
   Œ!Q            All unique permutations
      Œɠ€         Run-length encode on each permutation
         ’§       Decrement and sum each
           2*S    Raise to power of 2 and sum

Проведіть кожен можливий маршрут на квадратній сітці. Кількість способів переміщення одиниць L в одну сторону як грак 2**(L-1). Застосовуйте це до кожного маршруту та підсумовуйте кількість способів проходу кожного маршруту.


Гарний підхід. Коли я переніс його до CJam, було коротше зменшити довжину, суму, а потім підняти 2 на суму; замість того, щоб підняти 2 на довжину, зменшити вдвічі, а потім помножити. Не знаєте, чи може це врятувати вам байт.
Пітер Тейлор

3

Вугілля , 44 31 байт

перекреслений 44 все ще є регулярним 44

F⊕θ«≔⟦⟧ηF⊕θ⊞ηΣ∨⁺ηEυ§λκ¹⊞υη»I⊟⊟υ

Спробуйте в Інтернеті! Пояснення: Працює шляхом обчислення кількості способів розділити трапецію протилежної довжини сторони m,nна трикутники, які лежать на цілих зміщеннях. Це просто загальний випадок прямокутника розміру nу питанні. Кількість розділів задається рекурсивно як суми чисел розділів для всіх сторін m,0..n-1і n,0..m-1. Це еквівалентно узагальненій проблемі граків, OEIS A035002 . Код просто обчислює кількість розділів, що працюють від 0,0до n,nвикористання раніше обчислених значень.

F⊕θ«

Петля над рядами 0..n.

≔⟦⟧η

Почніть з порожнього рядка.

F⊕θ

Проведіть петлю над стовпцями в ряд 0..n.

⊞ηΣ∨⁺ηEυ§λκ¹

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

⊞υη»

Додайте готовий рядок до списку рядків поки.

I⊟⊟υ

Виведіть обчислене кінцеве значення.




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