ช่วยด้วยฉันติดอยู่ในสามเหลี่ยม Sierpinski!


44

วาดรูปสามเหลี่ยม Sierpinski ได้รับการ ทำเพื่อ ความตาย มีสิ่งที่น่าสนใจอื่น ๆ ที่เราสามารถทำได้ หากเราเหลื่อมอย่างหนักที่สามเหลี่ยมเราสามารถดูรูปสามเหลี่ยมกลับหัวกลับหางเป็นโหนดของกราฟเศษส่วน ลองหาวิธีของเรารอบกราฟนั้น!

ก่อนอื่นเรามากำหนดหมายเลขให้แต่ละโหนด รูปสามเหลี่ยมคว่ำที่ใหญ่ที่สุดจะเป็นศูนย์โหนดและจากนั้นเราก็ลงเลเยอร์ทีละเลเยอร์

ป้อนคำอธิบายรูปภาพที่นี่
คลิกเพื่อดูเวอร์ชั่นที่ใหญ่ขึ้นซึ่งตัวเลขขนาดเล็กจะเบลอน้อยลง

(แน่นอนรูปแบบนี้ยังคงไม่มีที่สิ้นสุดภายในรูปสามเหลี่ยมสีฟ้า.) วิธีการกำหนดเลขก็คือว่าโหนดกลางมีดัชนี0และเด็กของโหนดi(รูปสามเหลี่ยมที่อยู่ติดกันของระดับถัดไปที่มีขนาดเล็ก) มีดัชนี3i+1, และ3i+23i+3

เราจะย้ายกราฟนี้อย่างไร มีขั้นตอนตามธรรมชาติได้ถึงหกขั้นตอนที่เราสามารถเลือกได้จากรูปสามเหลี่ยมใด ๆ

  • เราสามารถเคลื่อนที่ผ่านจุดกึ่งกลางของขอบหนึ่งไปยังหนึ่งในสามลูกของโหนดปัจจุบัน เราจะกำหนดให้การเคลื่อนไหวเหล่านี้เป็นN, และSW SEเช่นถ้าเราอยู่บนโหนด2เหล่านี้จะนำไปสู่ต่อมน้ำ7, 8, 9ตามลำดับ การเคลื่อนไหวอื่น ๆ ผ่านขอบ (ไปยังลูกหลานทางอ้อม) ไม่ได้รับอนุญาต
  • เราสามารถเลื่อนมุมหนึ่งในสามมุมนี้ได้โดยที่ไม่แตะที่ขอบของสามเหลี่ยมเพื่อไปยังผู้ปกครองโดยตรงหรือบรรพบุรุษทางอ้อมหนึ่งในสองคน เราจะกำหนดให้การเคลื่อนไหวเหล่านี้เป็นS, และNE NWเช่นถ้าเราอยู่บนโหนด31, Sจะนำไปสู่10, NEจะไม่ถูกต้องและจะนำไปสู่NW0

ความท้าทาย

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

โปรดทราบว่ารหัสของคุณควรใช้งานได้มากกว่า 5 ระดับที่อธิบายไว้ในแผนภาพด้านบน x, y < 1743392200คุณอาจจะคิดว่า สิ่งนี้ทำให้มั่นใจได้ว่ามันพอดีกับจำนวนเต็ม 32 บิต โปรดทราบว่าสิ่งนี้สอดคล้องกับ 20 ระดับของต้นไม้

รหัสของคุณจะต้องดำเนินการป้อนข้อมูลที่ถูกต้องใด ๆ ในน้อยกว่า 5 วินาที ในขณะที่กฎนี้ออกค้นหาความกว้างเดียรัจฉานครั้งแรกมันควรจะเป็นข้อ จำกัด ที่ค่อนข้างหลวม - การอ้างอิงของฉันจัดการกับการป้อนข้อมูลโดยพลการสำหรับความลึก 1,000 ในครึ่งวินาที (นั่นคือ ~ 480 ตัวเลขหลักสำหรับโหนด)

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

เอาท์พุทควรจะแบนรายการที่ชัดเจนของสตริงN, S, NE, NW, SE, SWใช้คั่นที่เหมาะสมใด ๆ (พื้นที่, linefeeds จุลภาค","... )

ใช้กฎมาตรฐานของ

กรณีทดสอบ

กรณีทดสอบสองสามข้อแรกนั้นสามารถทำได้ด้วยมือโดยใช้แผนภาพด้านบน คนอื่น ๆ มั่นใจได้ว่าคำตอบนั้นมีประสิทธิภาพเพียงพอ สำหรับผู้ที่อาจมีวิธีการแก้ปัญหาอื่น ๆ ที่มีความยาวเท่ากันที่ไม่ได้ระบุไว้

0 40                    => N N N N
66 67                   => S SW N N N
30 2                    => NW NW -or- NE SW
93 2                    => NE SW
120 61                  => NW NW NW NW N SE SW N
1493682877 0            => S S NW NW
0 368460408             => SW SW N N SW SW SE SW SW N SE N N SW SW N SE SE
1371432130 1242824      => NW NW NE NW N SE SW SW SW SE SE SW N N N N SW
520174 1675046339       => NE NW NE NE SE SE SW SW N SE N SW N SW SE N N N N SE SE SW SW
312602548 940907702     => NE NW S SW N N SW SE SE SE SW SE N N SW SE SE SE SW
1238153746 1371016873   => NE NE NE SE N N SW N N SW N SE SE SW N SW N N SE N SE N
547211529 1386725128    => S S S NE NW N N SE N SW N SE SW SE SW N SE SE N SE SW SW N
1162261466 1743392199   => NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE

คำตอบ:


5

ทับทิม, 195 194 190 184 ไบต์

Original:ด้วยคำขอโทษของEllเนื่องจากเป็นคำตอบของพวกเขาและขอบคุณDoorknob ที่ช่วยพวกเขาในการแก้ไขข้อผิดพลาดนี้ อาจมีอัลกอริทึมอื่นสำหรับปัญหานี้ - สิ่งที่ต้องทำ*f[x[0,**however far x matches with y**],y]- แต่ฉันจะบันทึกไว้อีกครั้ง

a=->n{n<1?[]:a[~-n/3]+[-n%3]}
f=->x,y{j=x.size
(Array===x)?x==y[0,j]?y[j..-1].map{|m|%w[SE SW N][m]}:x.uniq.map{|m|[%w[NW NE S][m],*f[x[0,x.rindex(m)],y]]}.min_by(&:size):f[a[x],a[y]]}

แก้ไข: อัลกอริทึมโลภไม่ทำงานสำหรับ h[299792458, 1000000]ฉันได้นับไบต์กลับไปที่ 195 ในขณะที่ฉันซ่อมแซมอัลกอริทึมของฉันอีกครั้ง คงเพียงสำหรับการนับไบต์จะเพิ่มขึ้นถึง 203 เฮ้อ

ภายใต้การก่อสร้าง:โปรแกรมนี้ใช้อัลกอริทึมโลภเพื่อค้นหาบรรพบุรุษร่วมกันx[0,j]==y[0,j](หมายเหตุ: อาจมีบรรพบุรุษร่วมหลายคน) อัลกอริทึมนั้นมีพื้นฐานมาจากการค้นหาบรรพบุรุษแบบเรียกซ้ำของEllมาก ๆ y[j..-1]ในช่วงครึ่งแรกของคำสั่งที่เกิดขึ้นเป็นวิธีการที่จะได้รับบรรพบุรุษร่วมกันนี้และช่วงครึ่งปีหลังจะได้รับการปีขึ้นอยู่กับ

หมายเหตุ: a[n]ที่นี่ส่งกลับฐานที่ 3 เลข bijectiveใช้ตัวเลขแทน2,1,01,2,3

ตัวอย่างเช่นสมมติวิ่งผ่านหรือf[59,17] ที่นี่f[[2,0,2,1],[2,1,1]] j == 1ที่จะได้รับในการx[0,j]ที่เราจะไปหรือ0 NWจากนั้นเพื่อyไปที่ไป[1,1]หรือSW SW

a=->n{n<1?[]:a[~-n/3]+[-n%3]}
h=->m,n{x=a[m];y=a[n];c=[];j=x.size
(j=x.uniq.map{|m|k=x.rindex(m);x[0..k]==y[0..k]?j:k}.min
c<<%w[NW NE S][x[j]];x=x[0,j])until x==y[0,j]
c+y[j..-1].map{|m|%w[SE SW N][m]}}

45

Python 2 208 205 200 ไบต์

A=lambda n:n and A(~-n/3)+[-n%3]or[]
f=lambda x,y:f(A(x),A(y))if x<[]else["SSNEW"[m::3]for m in
y[len(x):]]if x==y[:len(x)]else min([["NNSWE"[m::3]]+f(x[:~x[::-1].index(m)],y)for
m in set(x)],key=len)

ฟังก์ชั่นfรับหมายเลขโหนดและส่งคืนพา ธ ที่สั้นที่สุดเป็นรายการสตริง

คำอธิบาย

เราเริ่มต้นด้วยการใช้รูปแบบการกำหนดที่แตกต่างกันสำหรับรูปสามเหลี่ยม ที่อยู่ของสามเหลี่ยมแต่ละรูปเป็นสตริงกำหนดดังนี้:

  • ที่อยู่ของสามเหลี่ยมกลางคือสตริงว่าง

  • ที่อยู่ของเด็กทางทิศเหนือทิศตะวันตกเฉียงใต้และทิศตะวันออกเฉียงใต้ของแต่ละรูปสามเหลี่ยมจะถูกผนวกเข้า0ด้วย1กันและ2ตามลำดับไปยังที่อยู่ของรูปสามเหลี่ยม

โดยพื้นฐานแล้วที่อยู่ของสามเหลี่ยมแต่ละรูปนั้นจะเข้ารหัสเส้นทาง (สั้นที่สุด) จากสามเหลี่ยมกลางไปยังเส้นทางนั้น สิ่งแรกที่โปรแกรมของเราทำคือแปลหมายเลขสามเหลี่ยมการป้อนข้อมูลไปยังที่อยู่ที่เกี่ยวข้อง

รูปที่ 1

คลิกที่ภาพเพื่อดูขนาดใหญ่ขึ้น

การเคลื่อนไหวที่เป็นไปได้ที่สามเหลี่ยมแต่ละอันนั้นหาได้ง่ายจากที่อยู่:

  • ที่จะย้ายไปทางทิศเหนือทิศใต้ทิศตะวันตกและเด็กตะวันออกเฉียงใต้เราก็ผนวก0, 1และ2ตามลำดับเพื่อที่อยู่

  • ที่จะย้ายไปทางทิศใต้, ภาคตะวันออกเฉียงเหนือและบรรพบุรุษทางตะวันตกเฉียงเหนือเราพบที่ผ่านมา (ขวาสุด) การเกิดขึ้นของ0, 1และ2ตามลำดับและตัดอยู่ไปทางซ้ายของมัน ถ้าไม่มี0, 1หรือ2ในที่อยู่แล้วบรรพบุรุษที่สอดคล้องกันไม่ได้อยู่ ตัวอย่างเช่นในการย้ายไปที่บรรพบุรุษตะวันตกเฉียงเหนือของ112(เช่นแม่) เราหาสิ่งที่เกิดขึ้นครั้งล่าสุดของ2ใน112ซึ่งเป็นตัวละครที่ผ่านมาและตัดอยู่ไปทางซ้ายของมันให้เรา11; ที่จะย้ายไปบรรพบุรุษภาคตะวันออกเฉียงเหนือเราพบว่าเกิดขึ้นครั้งล่าสุดของ1ใน112ซึ่งเป็นตัวละครที่สองและตัดอยู่ไปทางซ้ายของมันให้เรา1; อย่างไรก็ตาม112ไม่มีบรรพบุรุษทางใต้เนื่องจากไม่มี0 ตามที่อยู่

บันทึกบางสิ่งเกี่ยวกับที่อยู่คู่xและy:

  • หากxเป็นสตริงย่อยเริ่มต้นของyแล้วyจะเป็นลูกหลานของxและดังนั้นเส้นทางที่สั้นที่สุดจากxไปyเพียงแค่ตามเด็กที่สอดคล้องกันของแต่ละสามเหลี่ยมระหว่างxและy; ในคำอื่น ๆ ที่เราสามารถใช้แทนกันได้0, 1และ2ในy[len(x):]ด้วยN, SWและSEตามลำดับ

  • มิฉะนั้นให้iเป็นดัชนีของไม่ตรงกันครั้งแรกระหว่างและx yมีเส้นทางจากไม่มีเป็นxไปyไม่ได้ผ่านx[:i](ซึ่งเป็นเช่นเดียวy[:i]) เช่นที่บรรพบุรุษร่วมกันครั้งแรกและx yดังนั้นเส้นทางใด ๆ จากxการyต้องมาถึงx[:i]หรือหนึ่งของบรรพบุรุษของตนขอเรียกรูปสามเหลี่ยมนี้แล้วดำเนินการต่อไปz yในการมาจากxถึงzเราปฏิบัติตามบรรพบุรุษตามที่อธิบายไว้ข้างต้น เส้นทางที่สั้นที่สุดจากzถึงyถูกกำหนดโดยสัญลักษณ์แสดงหัวข้อก่อนหน้า

หากxเป็นสตริงย่อยเริ่มต้นของyแล้วเส้นทางที่สั้นที่สุดจากxถึงyจะได้รับได้อย่างง่ายดายโดยกระสุนแรกที่ด้านบน มิฉะนั้นเราจะปล่อยให้jเป็นที่เล็กที่สุดของดัชนีเกิดขึ้นสุดท้ายของ0, 1และใน2 xหากjมีค่ามากกว่าหรือเท่ากับดัชนีของไม่ตรงกันครั้งแรกระหว่างxและy, iเราก็เพิ่มย้ายที่สอดคล้องกัน ( S, NEหรือNWตามลำดับ) ไปยังเส้นทางตัดxไปทางซ้ายของjและดำเนินการต่อ สิ่งต่าง ๆ มีเล่ห์เหลี่ยมหากjน้อยกว่าiนั้นตั้งแต่นั้นเราอาจจะyเร็วที่สุดโดยขึ้นไปที่บรรพบุรุษร่วมกันx[:j]โดยตรงและลงไปจนถึงyหรือเราอาจสามารถเข้าถึงบรรพบุรุษร่วมกันที่แตกต่างกันxและyใกล้ชิดyโดยขึ้นไปยังบรรพบุรุษที่แตกต่างกันxไปทางขวาiและเดินทางจากที่นั่นไปyเร็วกว่า ตัวอย่างเช่นในการรับจาก1222ถึง1เส้นทางที่สั้นที่สุดคือการขึ้นไปที่สามเหลี่ยมแรก (ซึ่งที่อยู่คือสตริงว่าง) จากนั้นลงไปที่1เช่นการย้ายครั้งแรกจะพาเราไปทางซ้ายของจุดที่ไม่ตรงกัน อย่างไรก็ตามเพื่อให้ได้มา1222ถึง12เส้นทางที่สั้นที่สุดคือการขึ้นไปสู่122และจากนั้นไป12เช่นการเคลื่อนที่ครั้งแรกทำให้เราไปทางขวาของจุดที่ไม่ตรงกัน

ดังนั้นเราจะหาเส้นทางที่สั้นที่สุดได้อย่างไร โปรแกรม "ข้าราชการ" ใช้วิธีแรงเดรัจฉาน-ish พยายามย้ายไปได้ทั้งหมดเพื่อการใด ๆ ของบรรพบุรุษเมื่อใดก็ตามที่xไม่ได้เป็น substring yเริ่มต้นของ มันไม่ได้แย่อย่างที่คิด! มันจะแก้ปัญหากรณีทดสอบทั้งหมดรวมกันภายในหนึ่งหรือสอง

แต่ถ้าเช่นนั้นเราสามารถทำได้ดีกว่านี้อีก: หากมีบรรพบุรุษที่สามารถเข้าถึงได้โดยตรงมากกว่าหนึ่งคนทางด้านซ้ายของจุดที่ไม่ตรงกันเราจะต้องทดสอบคนที่ถูกที่สุดเท่านั้นและถ้ามีบรรพบุรุษที่สามารถเข้าถึงได้โดยตรงมากกว่าหนึ่งคน ด้านขวาของจุดที่ไม่ตรงกันเราจะต้องทดสอบทางซ้ายสุดเท่านั้น สิ่งนี้ให้อัลกอริธึมเชิงเส้นตรงเวลา, wrt ความยาวของx(เช่น, ความลึกของสามเหลี่ยมต้นทาง, หรือเวลาตามสัดส่วนกับลอการิทึมของหมายเลขสามเหลี่ยมต้นทาง), ซึ่งขยายผ่านกรณีทดสอบที่ใหญ่กว่ามาก โปรแกรมต่อไปนี้ใช้อัลกอริทึมนี้อย่างน้อยก็ในสาระสำคัญ - เนื่องจากการเล่นกอล์ฟความซับซ้อนของมันคือในความเป็นจริงนั้นแย่กว่าเชิงเส้น แต่ก็ยังเร็วมาก

Python 2 271 266 261 ไบต์

def f(x,y):
 exec"g=f;f=[]\nwhile y:f=[-y%3]+f;y=~-y/3\ny=x;"*2;G=["SSNEW"[n::3]for
n in g];P=G+f;p=[];s=0
 while f[s:]:
    i=len(f)+~max(map(f[::-1].index,f[s:]));m=["NNSWE"[f[i]::3]]
    if f[:i]==g[:i]:P=min(p+m+G[i:],P,key=len);s=i+1
    else:p+=m;f=f[:i]
 return P

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

ผล

ตัวอย่างต่อไปนี้สามารถใช้เพื่อเรียกใช้การทดสอบสำหรับทั้งสองเวอร์ชันและสร้างผลลัพธ์:

def test(x, y, length):
    path = f(x, y)
    print "%10d %10d  =>  %2d: %s" % (x, y, len(path), " ".join(path))
    assert len(path) == length

#         x           y        Length
test(          0,          40,    4   )
test(         66,          67,    5   )
test(         30,           2,    2   )
test(         93,           2,    2   )
test(        120,          61,    8   )
test( 1493682877,           0,    4   )
test(          0,   368460408,   18   )
test( 1371432130,     1242824,   17   )
test(     520174,  1675046339,   23   )
test(  312602548,   940907702,   19   )
test( 1238153746,  1371016873,   22   )
test(  547211529,  1386725128,   23   )
test( 1162261466,  1743392199,   38   )

เวอร์ชัน Golfed

         0         40  =>   4: N N N N
        66         67  =>   5: S SW N N N
        30          2  =>   2: NE SW
        93          2  =>   2: NE SW
       120         61  =>   8: NW NW NW NW N SE SW N
1493682877          0  =>   4: S S NW NW
         0  368460408  =>  18: SW SW N N SW SW SE SW SW N SE N N SW SW N SE SE
1371432130    1242824  =>  17: NW NW NE NW N SE SW SW SW SE SE SW N N N N SW
    520174 1675046339  =>  23: NE NE NE NE SE SE SW SW N SE N SW N SW SE N N N N SE SE SW SW
 312602548  940907702  =>  19: NE NW S SW N N SW SE SE SE SW SE N N SW SE SE SE SW
1238153746 1371016873  =>  22: NE NE NE SE N N SW N N SW N SE SE SW N SW N N SE N SE N
 547211529 1386725128  =>  23: S S S S NW N N SE N SW N SE SW SE SW N SE SE N SE SW SW N
1162261466 1743392199  =>  38: NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE

เวอร์ชันที่มีประสิทธิภาพ

         0         40  =>   4: N N N N
        66         67  =>   5: S SW N N N
        30          2  =>   2: NW NW
        93          2  =>   2: NE SW
       120         61  =>   8: NW NW NW NW N SE SW N
1493682877          0  =>   4: NE S NW NW
         0  368460408  =>  18: SW SW N N SW SW SE SW SW N SE N N SW SW N SE SE
1371432130    1242824  =>  17: NW NW NE NW N SE SW SW SW SE SE SW N N N N SW
    520174 1675046339  =>  23: NE NW NE NE SE SE SW SW N SE N SW N SW SE N N N N SE SE SW SW
 312602548  940907702  =>  19: NE NW S SW N N SW SE SE SE SW SE N N SW SE SE SE SW
1238153746 1371016873  =>  22: NE NE NE SE N N SW N N SW N SE SE SW N SW N N SE N SE N
 547211529 1386725128  =>  23: S S S S NW N N SE N SW N SE SW SE SW N SE SE N SE SW SW N
1162261466 1743392199  =>  38: NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE SE

6
ประณามอย่างรวดเร็ว ฉันไม่สามารถบอกคุณได้ว่ามันมีความสุขแค่ไหนที่ทำให้ฉันทุกครั้งที่ฉันให้คุณตอบคำถามท้าทายของฉัน :)
Martin Ender

2
@ MartinBüttnerขอบคุณมากนั่นเป็นคำชม! FWIW ฉันสนุกกับการแก้ปัญหาของคุณอย่างมหาศาล ฉันอาจหรืออาจจะไม่ได้เริ่มต้นการทำงานในหนึ่งนี้ในขณะที่มันยังคงอยู่ใน sandbox ... :)
Ell

2
รูปแบบการกำหนดแอดเดรสนั้นยอดเยี่ยม นี่มันเจ๋งมาก.
BrainSteel

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

1
@Zymus ผมไม่แน่ใจว่าผมทำตาม แต่ถ้าคุณหมายถึงภาพที่มันไม่ควรจะตรงกับ OP-นี้เป็นโครงการที่อยู่ที่แตกต่างกันตามที่อธิบายในการโพสต์.
Ell

3

APL (Dyalog Unicode) , 144 132 129 118 133 132 130 124 117 ไบต์SBCS

ขอบคุณมากที่ Ven และ ngn สำหรับความช่วยเหลือในการเล่นกอล์ฟในThe APL Orchardซึ่งเป็นสถานที่ที่ดีในการเรียนรู้ภาษา APL ⎕IO←0. ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ

แก้ไข: -12 ไบต์ขอบคุณ Ven และ ngn โดยการเปลี่ยนวิธีการnกำหนดและสลับจากการทำดัชนี 1 ครั้งเป็น 0 การจัดทำดัชนี -3 เนื่องจากการแก้ไขข้อผิดพลาดที่ไม่ใช่ทุกอย่างถูกเปลี่ยนเป็นดัชนี 0 -11 ไบต์เนื่องจากการเปลี่ยนแปลงวิธีPและQกำหนด +15 ไบต์เนื่องจากการแก้ไขปัญหาที่อัลกอริทึมของฉันไม่ถูกต้องขอบคุณมากด้วย ngn สำหรับความช่วยเหลือในการหาs[⊃⍋|M-s]ส่วน -2 ไบต์จากการจัดเรียงวิธีการค้นหาเส้นทางย้อนรอยและ +1 ไบต์เพื่อแก้ไขข้อผิดพลาด -2 Iไบต์ขอบคุณที่อดัมจากการจัดเรียงนิยามของ -6 ไบต์ขอบคุณ ngn จากการจัดเรียงคำจำกัดความใหม่'S' 'NE' 'NW' 'N' 'SW' 'SE'และจากการจัดเรียงใหม่tตามที่นิยามไว้ (ไม่ใช่ตัวแปรที่แยกต่างหาก) -7 ไบต์ขอบคุณ ngn จากการเล่นกอล์ฟว่าsมีการกำหนดอย่างไร

{M←⊃⍸≠⌿↑1+P Q←⍵{(⍵/3)⊤⍺-+/3*⍳⍵}¨⌊31+⍵×2⋄(∪¨↓6 2'SSNENWNNSWSE')[P[I],3+Q↓⍨⊃⌽I←⍬{M≥≢⍵:⍺⋄(⍺∘,∇↑∘⍵)s[⊃⍋|M-s←⌽⊢.⊢⌸⍵]}P]}

ลองออนไลน์!

คำอธิบายของข้อบกพร่องในอัลกอริทึม

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

จาก 66 ถึง 5

66  0 2 2 2  0 2 2 2
5   0 1      0 1
       common ancestor

The two ancestors of 0 2 2 2 are:
0 2 2
(empty)

(empty) has the shorter path back to 0 1 as it only needs two forward moves,
while 0 2 2 requires two more backtracks and one more forward move.

จาก 299792458 ถึง 45687

299792458  0 2 1 1 0 1 1 2 1 1 1 2 1 0 2 2 2 0
45687      0 2 1 1 0 1 1 1 2 2
                          common ancestor

The three ancestors of 299792458 are:
0 2 1 1 0 1 1 2 1 1 1 2 1 0 2 2 2
0 2 1 1 0 1 1 2 1 1 1 2             choose this one
0 2 1 1 0 1 1 2 1 1 1 2 1 0 2 2

And the three ancestors of 0 2 1 1 0 1 1 2 1 1 1 2 are:
0 2 1 1
0 2 1 1 0 1 1 2 1 1
0 2 1 1 0 1 1 2 1 1 1

0 2 1 1 0 1 1 1 2 2     45687 for reference
              common ancestor

While it seems like `0 2 1 1` is the shorter path,
it actually results in a path that is 8 steps long
(2 backtracks, 6 forward steps to 45687).

Meanwhile, `0 2 1 1 0 1 1 2 1 1` is at an equal distance
to the common ancestor and has the following ancestors:
0 2 1 1
0 2 1 1 0 1 1 2 1
0 2 1 1 0 1 1

0 2 1 1 0 1 1 1 2 2     45687 for reference
              common ancestor

Clearly, this is the superior path, as with three backtracks, we have reached
the point of the common ancestor. With 3 backtracks and 3 forward moves,
we have a path that is 6 steps long.

คำอธิบายของรหัส

                         should be an array of 2 integers, x y
SierpinskiPath←{⎕IO0   0-indexing
         P Q←{...}¨⍵   First, the bijective base-3 numeration of x and y
    P Q←{
        n←⌊31+⍵×2   The number of digits in the numeration
        z←+/3*⍳⍵     The number of numerations with  n digits
        (n/3)⊤⍵-z    And a simple decode  (base conversion) of ⍵-z
    }¨⍵              gets us our numerations, our paths

    A←↑1+P Q       We turn (1+P Q) into an 2-by-longest-path-length array 
                    pads with 0s and our alphabet also uses 0s
                   So we add 1 first to avoid erroneous common ancestor matches
    Common←⊃⍸≠⌿A   We find the length of the common ancestor, Common

         I←⍬{...}P   Now we get the shortest backtracking path from P
    I←⍬{
        Common=≢⍵:⍺        If P is shorter than Common, return our backtrack path
        s←⌽⊢.⊢⌸⍵           Get the indices of the most recent N SW SE
        ts[⊃⍋|Common-s]   and keep the index that is closest to Common
                           and favoring the ancestors to the right of
                           Common in a tiebreaker (which is why we reverse ⊢.⊢⌸⍵)
        (⍺,t)∇t↑⍵          Then repeat this with each new index to backtrack
    }P                     and the path left to backtrack through

    BacktrackP[I]    We get our backtrack directions
    Forward←(⊃⌽I)↓Q   and our forward moves to Q
                      starting from the appropriate ancestor
    (∪¨↓6 2'SSNENWNNSWSE')[Backtrack,Forward]     'S' 'NE' 'NW' 'N' 'SW' 'SE'
}                     and return those directions

โซลูชันทางเลือกโดยใช้ Dyalog Extended และ dfns

ถ้าเราใช้⎕CY 'dfns'ของadicฟังก์ชั่นก็ดำเนิน bijective ฐาน n เลขของเรา (ซึ่งเป็นแรงบันดาลใจสำหรับการใช้งานรุ่น I) สำหรับไบต์ไกลน้อย การเปลี่ยนมาใช้ Dyalog Extended ยังช่วยประหยัดจำนวนไบต์ได้ดังนั้นที่นี่เรา ขอบคุณAdámมากสำหรับความช่วยเหลือในการตีกอล์ฟนี้ ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ!

แก้ไข: -8 ไบต์เนื่องจากการเปลี่ยนแปลงวิธีPและQกำหนด -14 ไบต์เนื่องจากเปลี่ยนเป็น Dyalog Extended -2 {}เนื่องจากการใช้โปรแกรมเต็มไปลบวงเล็บ +17 ไบต์เนื่องจากการแก้ไขปัญหาที่อัลกอริทึมของฉันไม่ถูกต้องขอบคุณมากด้วย ngn สำหรับความช่วยเหลือในการหาs[⊃⍋|M-s]ส่วน +1 ไบต์เพื่อแก้ไขข้อบกพร่อง -2 ไบต์ขอบคุณที่อดัมจากการจัดเรียงนิยามของI และ -1 ไบต์จากความทรงจำที่จะนำโรงแรมพร้อมสนามกอล์ฟของฉันในการแก้ปัญหาทั้ง -3 ไบต์ด้วย ngn โดยจัดเรียงทิศทางของคาร์ดินัลใหม่, +1 byte จากการแก้ไข buggy golf, และ -3 bytes ขอบคุณ ngn โดยการจัดเรียงใหม่tตามที่นิยามไว้ (ไม่ใช่ตัวแปรที่แยกต่างหาก) -7 ไบต์ขอบคุณ ngn โดยการจัดเรียงใหม่sตามที่กำหนดไว้

APL (ส่วนขยายของ Dyalog) , 123 115 101 99 116 117 114 109 102 ไบต์

M←⊃⍸≠⌿↑1+P Q←(⍳3)∘⌂adic¨⎕⋄(∪¨↓6 2'SSNENWNNSWSE')[P[I],3+Q↓⍨⊃⌽I←⍬{M≥≢⍵:⍺⋄(⍺∘,∇↑∘⍵){⍵[⊃⍋|M-⍵]}⌽⊢.⊢⌸⍵}P]

ลองออนไลน์!


สำหรับ 66 และ 1 สิ่งนี้ไม่พบวิธีที่สั้นที่สุดผ่านทาง 0
Christian Sievers

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