Кількість обшивок доміно


9

Напишіть програму або функцію, яка за позитивних n і m обчислює кількість дійсних чітко виражених домінок для доміно, які можна помістити в прямокутник n на m . Це послідовність A099390 в Інтернет-енциклопедії цілих послідовностей . Ви можете приймати дані у вигляді аргументів (аргументів), CLA або stdin у будь-якому розумному форматі. Ви повинні повернути або роздрукувати одне ціле число як вихід.

Кожна плитка не повинна залишати жодних прогалин, і кожне чітке облицювання обчислюється, включаючи обертання, відбиття тощо. Наприклад, обшивки для 2x3:

|--    |||    --| 
|--    |||    --|

Приклади входів / виходів:

1,  9 -> 0
2,  2 -> 2
2,  3 -> 3
4,  4 -> 36
4,  6 -> 281
6,  6 -> 6728
7, 10 -> 53175517

Ваша програма теоретично повинна працювати для будь-яких n і m , але якщо вашій програмі потрібно занадто багато пам'яті або ваш тип даних переповнюється, це виправдано. Програма повинна працювати правильно для будь-якого n, m <= 8, однак.


Виграє найкоротший код у байтах.


Ви могли б набагато полегшити наше життя, якби ви дозволили лише 2n x 2m зони , приємний виклик!
невдача

Так само, як це питання codegolf.stackexchange.com/q/51067/15599 лише коротше і повільніше
рівень річки Сент

@ edc65 Damnit = / Я, здається, не думаю про щось нове ... Майже кожен виклик, про який я думаю, вже був виконаний у якійсь формі. Так чи інакше, виклики точно не однакові, оскільки моє питання - це кодовий гольф, і вам не доведеться знаходити перекриття - лише їх кількість. Можливо, люди можуть використовувати приємні формули замість того, щоб писати брутафорсер.
orlp

Домовились - збираємось видалити інший коментар
edc65

Скопійований коментар bilbo (який він опублікував як відповідь через 1 повтор): "Ця проблема є проблемою SPOJ, яка скорочується: spoj.com/problems/MNTILE Найкоротший код на SPOJ - 98 байт у див." . Здається, я вдвічі неоригінальний - я не знав про це.
orlp

Відповіді:


3

Pyth, 30 29 байт

L?bsmy-tb]dfq1.a-VThbb1y*FUMQ

Спробуйте в Інтернеті: Демонстрація / Тестовий набір

Усі приклади входів працюють в онлайн-компіляторі. Остання, однак, займає кілька секунд.

Пояснення:

У своєму коді я визначу рекурсивну функцію y. Функція yприймає список 2D-координат і повертає кількість різних накладок доміно за допомогою цих координат. Наприклад y([[0,0], [0,1]]) = 1(одне горизонтальне доміно), y([[0,0], [1,1]]) = 0(координати не є суміжними) та y([[0,0], [0,1], [1,0], [1,1]]) = 2(або два горизонтальних, або два вертикальних доміно). Після визначення функції я буду називати його з усіма координатами [x,y]з x in [0, 1, m-1], y in [0, 1, n-1].

Як працює рекурсивна функція? Це досить просто. Якщо список кодорів порожній, є рівно одна дійсна плитка та yповертається 1.

В іншому випадку я беру першу координату у списку b[0], а інші координати шукаю для сусідів. Якщо немає сусіда b[0], то немає можливого облицювання плитки, тому я повертаю 0. Якщо є один або більше сусідів, то кількість перекриттів дорівнює (кількість обрізів, де я з'єднуюся b[0]з першим сусідом через доміну, плюс кількість нахилів, де я з'єднуюся b[0]з другим сусідом, плюс ...) Тому я називаю функцію рекурсивно для кожного сусіда зі скороченим списком (видаляючи два координати b[0]та сусіда). Потім я підбиваю всі результати і повертаю їх.

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

                          UMQ  convert the input numbers into ranges
                        *F     Cartesian product (coords of each square)
L                              define a function y(b):
 ?b                              if len(b) > 0:
           f         b             filter b for squares T, which satisfy:
              .a-VThb                Euclidean distance between T and b[0]
            q1                       is equal to 1 (direct neighbors)
    m                              map each neighbor d to:
      -tb]d                          remove d from b[1]
     y                               and call recursively y with the rest
   s                               sum all those values and return them
                                 else:
                      1            return 1 (valid domino tiling found)
                       y*FUMQ  Call y with all coords and print the result  

Чи можете ви розповісти нам трохи більше про те, як працює ваша програма? Я не міг з'ясувати ваш алгоритм із коментарів.
flawr

@flawr Я додав пояснення свого алгоритму.
Якубе

@Jaketube Дякую за пояснення, мені дуже подобається рекурсивний підхід!
недолік

3

Матлаб, 292

Я впевнений, що це можна значно скоротити, перенісши його іншою мовою.

Основна ідея - жорстока: я придумав своєрідне перерахування всіх способів розміщення m*n/2цегли доміно на m*nдошці. Але це перерахування включає також багато недійсних обшивок (цегли, які перекриваються або виходять за межі дошки.) Отже, програма побудує всі ці обшивки і підраховує лише дійсні. Складність виконання приблизно O(2^(m*n/2) * m*n). Пам'ять не є проблемою, 8x8оскільки їй потрібна лише O(m*n)пам'ять. Але час, необхідний для цього, 8x8становить близько 20 днів.

Тут повністю коментована версія, яка пояснює, що відбувається.

PS: Якщо хтось знає, як зробити підсвічування синтаксису Matlab, будь ласка, включіть відповідний тег у цю відповідь!

function C=f(m,n)
d = ceil(m*n/2);%number of dominoes
%enumeration: %the nth bit in the enumeration says whether the nth 
% domino pice is upright or not. we enumerate like this:
% firt piece goes top left:
% next piece goes to the left most column that has an empty spot, in the
% top most empty spot of that column
C=0;%counter of all valid tilings
for e=0:2^d-1 %go throu all enumerations
    %check whether each enumeration is valid
    A = ones(m,n);
    %empty spots are filled with 1
    %filled spots are 0 (or if overlapping <0) 
    v=1;%flag for the validity. hte grid is assumed to be valid until proven otherwise
    for i=1:d %go throu all pieces, place them in A
        %find the column where to place:
        c=find(sum(A)>0,1);
        %find the row where to place:
        r=find(A(:,c)>0,1);
        %find direction of piece:
        b=de2bi(e,d);
        if b(i)
            x=0;y=1;
        else
            x=1;y=0;
        end
        %fill in the piece:
        try
            A(r:r+y,c:c+x)=A(r:r+y,c:c+x)-1;
        catch z
            v=0;break;
        end
        %check whether A has no overlapping pieces
        if any(A(:)<0)
            v=0;break;
        end
    end
    %if valid, count it as valid
    if v && ~norm(A(:))
        disp(A)
        C=C+1;
    end
end

Тут повністю гольф:

function C=f(m,n);m=4;n=6;d=ceil(m*n/2);C=0;for e=0:2^d-1;A=ones(m,n);v=1;for i=1:d;c=find(sum(A)>0,1);r=find(A(:,c)>0,1);b=de2bi(e,d);if b(i);x=0;y=1;else;x=1;y=0;end;try;A(r:r+y,c:c+x)=A(r:r+y,c:c+x)-1;catch z;v=0;break;end;if any(A(:)<0);v=0;break;end;end;if v && ~norm(A(:));C=C+1;end;end

2

C89, 230 байт

f(n,m,b)int*b;{int s,i;s=i=0;
while(b[i])if(++i==n*m)return 1;
if(i/n<m-1){b[i]=b[i+n]=1;s+=f(n,m,b);b[i]=b[i+n]=0;}
if(i%n<n-1&&!(b[i]|b[i+1])){b[i]=b[i+1]=1;s+=f(n,m,b);b[i]=b[i+1]=0;}
return s;}
g(n,m){int b[99]={};return f(n,m,b);}

Для читабельності я переклав цю відповідь - всі нові рядки можна сміливо видалити, щоб дістати до 230 байт.

Визначає функцію, int g(int n, int m)яка повертає кількість нахилів. Він використовує допоміжну функцію, fяка ітералізує всі дійсні облицювання, розміщуючи одне доміно, повторюючи, а потім видаляючи доміно на загальній дошці.


0

Пітон 243

Я обрав підхід грубої сили:

  • генерувати m * n / 2 напрямки;
  • спробуйте помістити доміно на дошці m * n.

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

Ось код:

import itertools as t
m,n=input()
c,u=0,m*n
for a in t.product([0,1],repeat=u/2):
 l,k,r,h=[' ',]*u,0,'-|',[1,m]
 for t in a:
  l[k]=r[t]
  k+=h[t]   
  if k%m<m and k/m<n and l[k]==' ':l[k]=r[t]
  k=''.join(l).find(' ',1)
 if k<0:c+=1
print c
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.