จำนวนโดมิโนเอียง


9

เขียนโปรแกรมหรือฟังก์ชั่นที่ได้รับในเชิงบวกnและม.คำนวณจำนวน tilings โดมิโนที่แตกต่างกันที่ถูกต้องที่คุณสามารถใส่ในnโดยม.รูปสี่เหลี่ยมผืนผ้า นี่คือลำดับ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เพียงสั้นลงและช้าลง
Level River St

@ edc65 Damnit = / ฉันไม่คิดว่าจะมีอะไรแปลกใหม่ ... เกือบทุกความท้าทายที่ฉันคิดว่าได้ทำไปแล้วในบางรูปแบบ ไม่ว่าจะด้วยวิธีใดความท้าทายไม่เหมือนกันอย่างแน่นอนเนื่องจากคำถามของฉันคือการเขียนโค้ดกอล์ฟและคุณไม่จำเป็นต้องค้นหาความเอียง - เพียงปริมาณของสิ่งเหล่านั้น บางทีผู้คนสามารถใช้สูตรที่ดีแทนการเขียน bruteforcer
orlp

เห็นด้วย - จะลบความคิดเห็นอื่น ๆ
edc65

คัดลอกความคิดเห็นของบิลโบ (ซึ่งเขาโพสต์เป็นคำตอบเนื่องจาก 1 ตัวแทน): "ปัญหานี้เป็นความท้าทายSPOJ ที่สั้นลง: spoj.com/problems/MNTILEรหัสที่สั้นที่สุดใน SPOJ คือ 98 ไบต์ใน awk" . ดูเหมือนว่าฉันไม่ใช่คนดั้งเดิม - ฉันไม่รู้
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]

ฟังก์ชั่นวนซ้ำทำงานอย่างไร มันค่อนข้างง่าย ถ้ารายการของ coords ว่างเปล่ามีอีกหนึ่งการปูกระเบื้องที่ถูกต้องและผลตอบแทนy1

มิฉะนั้นฉันจะใช้พิกัดแรกในรายการb[0]และค้นหาพิกัดที่เหลือสำหรับเพื่อนบ้าน หากไม่มีเพื่อนบ้านไปb[0]แล้วก็ไม่มีกระเบื้องที่เป็นไปได้ดังนั้นฉันกลับ 0 หากมีเพื่อนบ้านหนึ่งคนหรือมากกว่านั้นจำนวนของกระเบื้องก็คือ (จำนวนของกระเบื้องที่ฉันเชื่อมต่อb[0]กับเพื่อนบ้านแรกผ่านโดมิโนบวก จำนวนการเอียงที่ฉันเชื่อมต่อb[0]กับเพื่อนบ้านที่สองบวก ... ) ดังนั้นฉันจึงเรียกใช้ฟังก์ชั่นซ้ำ ๆ สำหรับแต่ละเพื่อนบ้านด้วยรายการที่สั้นลง (โดยลบทั้งสองสายb[0]และเพื่อนบ้าน) หลังจากนั้นฉันก็สรุปผลทั้งหมดแล้วคืนพวกเขา

เนื่องจากลำดับของ coords จะมีเพียงสองประเทศเท่านั้นที่เป็นไปได้เพื่อนบ้านทางด้านขวาและด้านล่าง แต่อัลกอริทึมของฉันไม่สนใจสิ่งนั้น

                          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 ฉันเพิ่มคำอธิบายของอัลกอริทึมของฉัน
Jakube

@ Jaketube ขอบคุณสำหรับคำอธิบายฉันชอบวิธีการแบบวนซ้ำ!
ข้อบกพร่อง

3

Matlab, 292

ฉันแน่ใจว่านี่สามารถย่อให้สั้นลงได้มากเพียงแค่โอนย้ายเป็นภาษาอื่น

แนวคิดพื้นฐานคือการดุร้าย: ฉันคิดวิธีการวางm*n/2อิฐโดมิโนบนm*nกระดาน แต่การแจงนับนี้ยังรวมถึงการเอียงที่ไม่ถูกต้องจำนวนมาก (อิฐที่ทับซ้อนกันหรือออกไปด้านนอกของบอร์ด) ดังนั้นโปรแกรมจะสร้างการเอียงเหล่านั้นทั้งหมดและนับเฉพาะจำนวนที่ถูกต้องเท่านั้น ความซับซ้อน runtime 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

นี่คือหนึ่ง golfed อย่างเต็มที่:

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

Python 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.