ฟีโบนัชชีโดมิโนปูกระเบื้อง


11

มีผล combinatorial คลาสสิกที่หลายวิธีที่จะกระเบื้อง2*nแถบโดย1*2แต้มเป็นที่ n THจำนวนฟีโบนักชี เป้าหมายของคุณคือการพิมพ์ความลาดเอียงทั้งหมดเพื่อให้nวาดด้วยขีดกลางและเส้นแนวตั้งเช่น 8 เอียงเหล่านี้สำหรับn=5:

|————
|————

——|——
——|——

|||——
|||——

————|
————|

||——|
||——|

|——||
|——||

——|||
——|||

|||||
|||||

คุณต้องจัดเตรียมโปรแกรมหรือฟังก์ชั่นที่มีชื่อซึ่งใช้nเป็นอินพุตและพิมพ์เอาต์พุตที่ต้องการ ไบต์ที่น้อยที่สุดจะเป็นผู้ชนะ

อินพุต

ตัวเลขnระหว่าง1และ10รวมผ่าน STDIN หรืออินพุตฟังก์ชัน

เอาท์พุต

พิมพ์ทุกโดมิโนที่เป็นไปได้ของ2*nแถบที่วาดในแนวนอน รอยยิ้มอาจอยู่ในลำดับใดก็ได้ แต่แต่ละอันควรปรากฏอย่างแน่นอนหนึ่งครั้ง จะต้องคั่นด้วยบรรทัดว่าง

โดมิโนแนวตั้งทำจากแท่งแนวตั้งสองอัน ( |) และโดมิโนแนวนอนทำจากเครื่องหมายขีดกลางสองอัน ( ) คุณอาจใช้เครื่องหมายขีดกลาง ( -) แทนเครื่องหมายขีดกลางเพื่ออยู่ใน ASCII

คุณสามารถทำอะไรกับช่องว่างตราบเท่าที่ผลลัพธ์ที่พิมพ์ออกมามีลักษณะเหมือนกัน


กับการวางเลื่อนบรรทัดพิเศษหลังจากที่ปูกระเบื้องฤดูใบไม้ร่วงที่ผ่านมาภายใต้การอะไรกับช่องว่าง ?
เดนนิส

@Dennis ใช่บรรทัดว่างพิเศษไม่เป็นไร
xnor

ฉันประหลาดใจจริงๆที่เห็นวิธีการมากมายในการแก้ปัญหาเดียวกัน คุณคาดหวังสิ่งนั้นหรือไม่
ระดับแม่น้ำเซนต์

@ steveverrill ไม่ฉันไม่ได้ทั้งหมดและยินดีที่ได้เห็นความหลากหลาย! และคุณก็เอาเค้กไปทำสิ่งที่คาดไม่ถึง ฉันมักจะนึกถึงการเรียกซ้ำแบบฟีโบนัชชีในขณะที่การแก้ปัญหาส่วนใหญ่ที่ฉันใช้ ฉันไม่ได้คาดหวังว่าการกรองจะมีประสิทธิภาพและเท่าที่ฉันทำแม้ว่าฉันจะกรองสตริง——และ|ตามความยาวเหมือนของเดนนิสไม่ใช่nสายยาวและ|กรองโดยปรากฏเป็นคู่ และสำหรับอันหลังฉันคาดหวังว่ามันจะผ่านการดำเนินการ regexes หรือสตริงบนสตริงที่ผลิตเช่นs.split('——) `ไม่ใช่ด้วยวิธีการทางคณิตศาสตร์เช่นเดียวกับคุณ
xnor

ฉันคิดว่า "1x2 แต้ม" ซ้ำซ้อน
SuperJedi224

คำตอบ:


5

C, 106

รุ่น Golfed

f(n){
  for(int i,h=n*2<<n;h--;(i/3|i/3*2)-i||(putchar(i>>h%n&1?45:124),h%n||puts(h%(n*2)?"":"\n")))
    i=h/2/n;
}

รุ่นเดิม

i,j,n;
main(){
  scanf("%d",&n);
  for(i=1<<n;i--;)if((i/3|i/3*2)==i){
    for(j=1<<n;j/=2;)printf("%c",i&j?'-':'|');puts("");
    for(j=1<<n;j/=2;)printf("%c",i&j?'-':'|');puts("\n");
  }
}

มันทำงานอย่างไร

ตัวแปรiวิ่งจาก1<<n-1ลงมาเป็น 0 เพื่อสร้างเลขฐานสองที่เป็นไปได้ทั้งหมดพร้อมnตัวเลข 0 ถอดรหัสสำหรับ|1 -และถอดรหัสสำหรับ เราสนใจตัวเลขที่มีจำนวน 1 คู่ เห็นได้ชัดว่าตัวเลขดังกล่าวหารด้วย 3

เมื่อตัวเลขถูกหารด้วย 3 หมายเลขเดิมจะสามารถกู้คืนได้โดยการคูณผลลัพธ์ด้วย 2 และเพิ่มเข้าไปในตัวเอง (การคูณได้อย่างมีประสิทธิภาพด้วย 3) ตัวเลขส่วนใหญ่จะต้องมีการพกพา แต่เมื่อกระบวนการดำเนินการกับตัวเลขของ ไม่มีความจำเป็นต้องถือติดตัวดังนั้นในกรณีเหล่านี้เท่านั้นหรือสามารถใช้แทนการเพิ่มได้ นี้จะใช้ในการทดสอบสำหรับตัวเลขที่น่าสนใจเช่นที่พวกเขาเป็นคนเดียวที่แสดงออกส่งกลับค่าเดิมของi/3|i/3*2 iดูตัวอย่างด้านล่าง

1111= 15 ---> 0101= 5 ---> 1111= 15 (ถูกต้อง0101|1010== 0101+1010)

1001= 9 ---> 0011= 3 ---> 0111= 7 (ไม่ถูกต้อง, 0011|0110! = 0011+0110)

ค่าทดสอบจะเท่ากับหรือน้อยกว่าค่าเดิมเสมอ เนื่องจากตัวเลขที่ไม่ใช่ทวีคูณของ 3 ก็ส่งกลับตัวเลขที่น้อยกว่าค่าเดิมเมื่อหารด้วย 3 แล้วคูณด้วย 3 การทดสอบจึงให้ค่า FALSE ที่ต้องการในตัวเลขเหล่านี้ด้วย

ในเวอร์ชันดั้งเดิมมีการใช้ลูปสองสามตัวในjการสแกนบิตiและสร้างเอาต์พุต ในรุ่นแข็งแรงเล่นกอล์ฟที่เดียวforห่วงถูกนำมาใช้ในการที่hไหลผ่านจำนวนทั้งหมดจาก(n*2)*(1<<n)-1ลงเป็น 0 ค่านิยมของถูกสร้างโดยi h/2/nตัวแปรjจะไม่ถูกใช้อีกต่อไปเนื่องจากได้รับปริมาณที่เท่าh%nกัน การใช้n*2ช่วยให้สามารถพิมพ์ทั้งสองบรรทัดจากลูปเดียวกันด้วยการใช้มัลติเพล็กซิ่งในputsคำสั่งเพื่อพิมพ์บรรทัดใหม่หนึ่งหรือสองบรรทัดที่ท้ายแถว

โปรดทราบว่าเนื้อนี้อยู่ในตำแหน่งที่เพิ่มขึ้นของfor()วงเล็บและดังนั้นจึงได้รับการดำเนินการหลังจากi=h/2/h

ตัวอย่างผลลัพธ์ n = 6:

$ ./a
6
------
------

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

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

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

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

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

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

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

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

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

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

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

||||||
||||||

i/3|i/3*2เคล็ดลับคือการที่แยบยล! ฉันไม่ได้คาดหวังว่าการแสดงออกทางคณิตศาสตร์สำหรับไวยากรณ์
xnor

3

CJam, 33 27 ไบต์

LN{_'|f+@"——"f++}ri*\;{_N}/

ขอบคุณ @ jimmy23013 สำหรับการเล่นกอล์ฟขนาด 6 ไบต์!

ลองออนไลน์!

พื้นหลัง

นี่เป็นการใช้งานซ้ำของอัลกอริทึมแบบเรียกซ้ำ:

tilings เป็นไปได้สำหรับnสามารถรับได้โดยการเพิ่มโดมิโนแนวตั้งที่จะเป็นไปได้สำหรับ tilings n - 1และแนวนอนสอง Dominos กับ tilings เป็นไปได้สำหรับn - 2

วิธีนี้จำนวน tilings สำหรับnคือผลรวมของจำนวน tilings สำหรับn - 1และn - 2คือจำนวนn th Fibonacci

มันทำงานอย่างไร

LN                                " A:= [''] B:= ['\n']                         ";
  {             }ri*              " Repeat int(input()) times:                  ";
   _'|f+                          "   C = copy(B); for T ∊ C: T += '|'          ";
              @                   "   Swap A and B.                             ";
               "——"f+             "   for T ∊ B: T += "——"                      ";
                     +            "   B = C + B                                 ";
                        \;        " Discard A.                                  ";
                          {_N}/   " for T ∊ B: print T, T + '\n'                ";

ตัวอย่างการวิ่ง

$ alias cjam='java -jar cjam-0.6.2.jar'

$ cjam domino.cjam <<< 3
|||
|||

——|
——|

|——
|——

$ for i in {1..10}; do echo $[$(cjam domino.cjam <<< $i | wc -l) / 3]; done1
2
3
5
8
13
21
34
55
89

LNli{_'|f\@"——"f\+2/}*\;{_N}/.
jimmy23013

f\ยังไม่ได้ใช้งานใน 0.6.2 แต่ฉันสามารถรวมวิธีการของเรา ขอบคุณ!
เดนนิส

2

Haskell, 89 ไบต์

f(-1)=[]
f 0=[""]
f n=map('|':)(f$n-1)++map("--"++)(f$n-2)
g=unlines.(>>= \x->[x,x,""]).f

fเป็นฟังก์ชั่นที่ให้ตัวเลขส่งคืนรายการหนึ่งบรรทัดของความเป็นไปได้ทั้งหมดของ Fibonacci tilings ที่มีความยาว n มันไม่สำคัญว่ามันจะคืนค่าหนึ่งบรรทัดเพราะทั้งสองบรรทัดของความเอียงทั้งหมดเท่ากัน

fทำงานโดยการเรียกซ้ำn-1และn-2และเพิ่ม"|"และ"--"(ตามลำดับ) ไปยังสตริง

gเป็นฟังก์ชั่นที่ตอบคำถาม มันเป็นพื้นเรียกร้องfให้อินพุทสองเท่าของทุก ๆ สตริงเพื่อที่มันจะแสดงสองบรรทัดและรวมพวกมันทั้งหมดโดยการขึ้นบรรทัดใหม่

เอาท์พุทตัวอย่าง:

*Main> putStrLn $ g 5
|||||
|||||

|||--
|||--

||--|
||--|

|--||
|--||

|----
|----

--|||
--|||

--|--
--|--

----|
----|

2

CJam, 42 37 ไบต์

3li:L#,{3b"——|"2/f=s}%{,L=},_&{N+_N}/

ฉันนับเครื่องหมายขีดคั่นเป็นหนึ่งไบต์เนื่องจากคำถามอนุญาตให้แทนที่ด้วยเครื่องหมายขีดกลาง ASCII

ลองออนไลน์

มันทำงานอย่างไร

ในการรับการเอียงที่เป็นไปได้ทั้งหมดของ2 × Lเราจะวนซ้ำจำนวนเต็มทั้งหมดที่ไม่ใช่ค่าลบI <3 Lทำให้ตัวเลขคู่ในฐาน 3 สอดคล้องกับแนวนอนและเลขหลักคี่กับแนวตั้ง

เนื่องจากแต่ละฉันมีLหรือตัวเลขน้อยลงในฐานที่ 3 นี้สร้างวิธีที่เป็นไปได้ทั้งหมดของการครอบคลุม2 × Lแถบ สิ่งที่เหลืออยู่คือการกรองแผ่นปิดที่ใหญ่กว่าหรือเล็กกว่า2 × Lและพิมพ์แผ่นปิดที่เหลือ

3li:L#,      " Read an integer L from STDIN and push A := [ 0 1 ... (3 ** N - 1) ].       ";
{            " For each integer I in A:                                                   ";
  3b         " Push B, the array of I's base 3 digits.                                    ";
  "——|"2/    " Push S := [ '——' '|' ].                                                    ";
  f=         " Replace each D in B with S[D % 2] (the modulus is implicit).               ";
  s          " Flatten B.                                                                 ";
}%           " Collect the result in an array R.                                          ";
{,L=},       " Filter R so it contains only strings of length L.                          ";
_&           " Intersect R with itself to remove duplicates.                              ";
{N+_N}/      " For each string T in B, push (T . '\n') twice, followed by '\n'.           ";

ตัวอย่างการวิ่ง

$ cjam domino.cjam <<< 3
|——
|——

——|
——|

|||
|||

$ for i in {1..10}; do echo $[$(cjam domino.cjam <<< $i | wc -l) / 3]; done
1
2
3
5
8
13
21
34
55
89

เย็น. ฉันแค่สงสัยว่าทำไมคุณไม่ใช้ฐาน 2 เช่น edc65 แทนที่จะเป็นฐาน 3 ซึ่งจะช่วยให้คุณประหยัดจากการซ้ำซ้อน 3bฉันคิดว่ามันเป็นเพราะศูนย์ชั้นนำอาจจะได้รับการตัดทอนในขั้นตอน นั่นถูกต้องใช่ไหม?
เลเวลริเวอร์เซนต์

1
@ สตีฟเวอร์ริลล์: ใช่นั่นคือเหตุผลอย่างแม่นยำ ตามที่เป็นอยู่ศูนย์นำหน้าจะไม่มีโดมิโนเลย แต่การไม่มีการซ้ำซ้อนจะทำให้ฉันสามารถแทนที่สามช่วงตึกด้วยบล็อกเดียว ฉันจะต้องคิดถึงเรื่องนี้ให้มากขึ้น
เดนนิส

@ สตีฟเวอร์ริลล์: ฉันไม่ได้จัดการที่จะทำให้ฐาน 2 ทำงานได้ แต่วิธีการแบบวนซ้ำดูเหมือนจะสั้นกว่านี้
เดนนิส

2

JavaScript (E6) 102

สร้างการกำหนดค่าจากลำดับบิต 0 -> '-' และ 1 -> '|'

F=n=>{
  for(i=0;(j=++i)<2<<n;s.length==1+n&&console.log('\n'+s+s))
    for(s='\n';j>1;j>>=1)s+=j&1?'|':'--';
}

ทดสอบในคอนโซล firefox / firebug

F(5)

เอาท์พุต

|----
|----

--|--
--|--

----|
----|

|||--
|||--

||--|
||--|

|--||
|--||

--|||
--|||

|||||
|||||

1

Haskell: 109 ไบต์

นี่คือคำแปลของ Haskell one-liner ที่เป็นที่รู้จักกันดีสำหรับการคำนวณแบบลำดับเลขฟีโบนักชีอย่างขี้เกียจ:

b=map.map.(++)
w=zipWith
z=w(++)
s=["\n"]:["|\n"]:z(b"--"s)(b"|"$tail s)
f=sequence_.map putStrLn.(w z s s!!)

ลำดับหลักของการเรียงสตริง, ungolfed:

dominos = [""] : ["|"] : zipWith (++) ("--" `before` dominos) ("|" `before` tail dominos)
    where before = map . map . (++)

และ Fibonacci One-liner สำหรับการเปรียบเทียบ:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

ตัวอย่างการใช้งาน:

$ ghci fibtile
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( fibtile.hs, interpreted )
Ok, modules loaded: Main.
*Main> f 5
----|
----|

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

*Main>

1

คอบร้า - 176

อดใจรอไม่ไหวที่ฉันจะได้เสร็จสิ้นแพ็คเกจการเล่นคอบร้า

def m(n)
    for t in.f(n),print t+t
def f(n,x='')as String*
    if x.length<n,for i in.f(n,x+'-').toList+.f(n,x+'|').toList,yield i
    else if not'-'in x.replace('--',''),yield x+'\n'

1

J - 54 ถ่าน

ฟังก์ชั่นการใช้nเป็นอาร์กิวเมนต์ทางด้านขวา

0{::(];'--'&,"1@[,'|',"1])&>/@[&0&((1 2$,:)&.>'';,'|')

(];'--'&,"1@[,'|',"1])&>/รากหลักของกีฬากอล์ฟแห่งนี้เป็น นี่ใช้รายการความยาว (N-2) และ (N-1) และส่งกลับรายการความยาว (N-1) และ N นี่คือการเกิดซ้ำแบบ Fibonacci มาตรฐานและพีชคณิตเชิงเส้น ];ส่งคืนรายการที่ถูกต้องเป็นด้านซ้ายใหม่ (เนื่องจากไม่มีการเปลี่ยนแปลง) '--'&,"1@[เพิ่ม--ไทล์ลงในรายการด้านซ้ายในขณะที่'|',"1]เพิ่ม|ไทล์ลงในรายการที่ถูกต้อง

เราย้ำว่ากว่าและมากกว่าnครั้ง (ที่@[&0) และเริ่มต้นด้วยการปูกระเบื้องที่ว่างเปล่าและปูกระเบื้องเดียวของความยาว 1 0{::แล้วเรากลับเป็นครั้งแรกของทั้งคู่ด้วย ความหมายถ้าเราเรียกมันว่าศูนย์ครั้งเราแค่คืนค่าแรกนั่นคือการปูกระเบื้องเปล่า หากเราเรียกใช้nครั้งเราคำนวณถึงnและ ( n+1) คู่ แต่ทิ้งหลัง มันเป็นงานพิเศษ แต่มีตัวอักษรน้อยกว่า

นี่(1 2$,:)คือสิ่งที่ J ต้องทำเพื่อให้สามารถขยายได้ในรายการได้อย่างง่ายดาย เราทำที่เหลือรายการเริ่มต้นเป็นรายการที่ 1 รายการของเมทริกซ์แถวที่ 2 ของตัวละครแต่ละแถวมีความยาว 0. รายการเริ่มต้นที่ถูกต้องคือเหมือนกัน แต่มีแถวที่มีความยาว 1 |ที่เต็มไปด้วย จากนั้นเราเพิ่มไทล์ใหม่ลงในแต่ละแถวและเพิ่มรายการเมทริกซ์เมื่อเราเข้าร่วมการเอียงสองชุดด้วยกัน มันเป็นแอปพลิเคชั่นที่เรียบง่ายของแนวคิด J ที่เรียกอันดับ: โดยพื้นฐานแล้วจัดการกับมิติของข้อโต้แย้งและวนลูปโดยปริยายเมื่อจำเป็น

   0{::(];'--'&,"1@[,'|',"1])&>/@[&0&((1 2$,:)&.>'';,'|')5
----|
----|

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

ลองด้วยตัวคุณเองที่tryj.tk


1

Python 3: 70 ไบต์

f=lambda n,s="\n":n>0and f(n-1,"|"+s)==f(n-2,"--"+s)or n or print(s*2)

สร้างสตริงที่เป็นไปได้ทั้งหมดซ้ำซึ่งsแสดงถึง Dominos แถวเดียวซึ่งทำซ้ำและพิมพ์ การเริ่มต้นsเป็นอักขระขึ้นบรรทัดใหม่ทำให้บรรทัดว่างเกิดขึ้นโดยอัตโนมัติ

==ระหว่างสองสายสำหรับการfเป็นเพียงการดำเนินการทั้งสองฟังก์ชั่นการโทร เหล่านี้มักจะกลับมาNoneเพราะพวกเขาเพียงแค่พิมพ์และเป็นหนึ่งของผู้ประกอบการไม่กี่กำหนดไว้สำหรับ==None

andและors มีการผลิตไฟฟ้าลัดวงจรพฤติกรรมที่เหมาะสมที่จะทำซ้ำifและelses ของรหัส ungolfed

Ungolfed:

def f(n,s="\n"):
 if n==-1:pass
 elif n==0: print(s*2)
 else: f(n-1,"|"+s);f(n-2,"--"+s)

1

เรติน่า 44 ไบต์

หมายเหตุ: Retina มีอายุน้อยกว่าความท้าทายนี้

+`([-|]*)11(1*#)
$1|1$2$1--$2
1
|
.*?#
$0$0#

รับอินพุตพร้อมกับขึ้นบรรทัดใหม่

แต่ละบรรทัดควรไปที่ไฟล์ของตนเองและ#ควรเปลี่ยนเป็นบรรทัดใหม่ในไฟล์ สิ่งนี้ไม่สามารถใช้งานได้ แต่คุณสามารถเรียกใช้รหัสได้เช่นเดียวกับไฟล์ที่มี-sแฟล็กโดยเก็บ#เครื่องหมาย (และเปลี่ยนบรรทัดใหม่#เป็นอินพุต) คุณสามารถเปลี่ยน#กลับเป็นบรรทัดใหม่ในผลลัพธ์เพื่อให้สามารถอ่านได้หากคุณต้องการ เช่น:

> echo 1111# | retina -s fib_tile | tr # '\n'
||||
||||

||--
||--

|--|
|--|

--||
--||

----
----

วิธี:

  • เริ่มต้นจากการป้อนข้อมูลที่เราสลับสอดคล้องกับอีกสองทุกหนึ่งเดียวกับครั้งแรกของ1การเปลี่ยนแปลง|และเป็นหนึ่งเดียวกับครั้งแรกที่สอง1's --เปลี่ยนไป เราทำเช่นนี้จนกว่าเราจะได้เส้นที่มีอย่างน้อยสอง1's
  • เมื่อมีคนเหลือคนเดียว1เราก็เปลี่ยนพวก|มันเป็น.
  • เราเพิ่มแต่ละบรรทัดเป็นสองเท่าและเพิ่มบรรทัดใหม่พิเศษลงไปและเราจะได้ผลลัพธ์ที่ต้องการ

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