ค้นหาตัวตนของทราย


18

คำถามนี้เป็นคำถามเกี่ยวกับsandpiles ศาสนาคริสต์ อ่านความท้าทายก่อนหน้านี้และดูวิดีโอเลขที่นี้เพื่อเรียนรู้เพิ่มเติม


กองทรายแบบอาเบลเรียนขนาดnคูณnเป็นตารางที่มีหมายเลข 0, 1, 2 และ 3 (แทนจำนวนเม็ดทราย) การเพิ่มทรายสองอันทำงานโดยการเพิ่มองค์ประกอบทีละองค์ประกอบก่อนจากนั้นจึงพลิกองค์ประกอบใด ๆ ที่สูงกว่า 3 ลำดับที่คุณโค่นล้มไม่สำคัญผลลัพธ์ที่ได้จะเหมือนกัน เมื่อเซลล์ล้มจำนวนลดลง 4 และแต่ละเพื่อนบ้านโดยตรงเพิ่มขึ้น 1 นี้สามารถทำให้เกิดปฏิกิริยาลูกโซ่ หากเซลล์อยู่บนขอบของตารางธัญพืชใด ๆ ที่หล่นลงมาจากตารางในขณะที่โค่นล้มหายไป

ตัวอย่างเช่นฉันกำลังเพิ่มทราย 2 3 คูณ 3 (ให้ปฏิกิริยาลูกโซ่ค่อนข้างรุนแรง):

3 3 3   1 2 1   4 5 4    4 6 4    6 2 6    6 3 6    2 5 2    4 1 4    4 2 4    0 4 0    2 0 2    2 1 2
3 3 3 + 2 1 2 = 5 4 5 -> 6 0 6 -> 2 4 2 -> 3 0 3 -> 5 0 5 -> 1 4 1 -> 2 0 2 -> 4 0 4 -> 0 4 0 -> 1 0 1
3 3 3   1 2 1   4 5 4    4 6 4    6 2 6    6 3 6    2 5 2    4 1 4    4 2 4    0 4 0    2 0 2    2 1 2

ในความท้าทายนี้เรากำลังสนใจในการย่อยของทั้งหมดที่เป็นไปได้nโดยn sandpiles เซ็ตย่อยนี้มี Sandpile ใด ๆ ที่คุณสามารถหาได้โดยเพิ่มแซนด์ไพล์แบบกำหนดเองไปยัง all-3s nโดยn sandpile ตัวอย่างเช่นเหนือเราเห็นว่า212 | 101 | 212อยู่ในส่วนย่อยเพราะเราได้รับมันโดยการเพิ่มบางสิ่งบางอย่างลงในทรายทั้ง 3

ตอนนี้ชุดย่อยนี้มีองค์ประกอบที่น่าสนใจ: องค์ประกอบตัวตน หากคุณนำองค์ประกอบนี้และเพิ่มไปยังองค์ประกอบอื่น ๆ ในชุดย่อยผลรวมจะไม่เปลี่ยนแปลง กล่าวอีกนัยหนึ่ง sandpile นี้ทำหน้าที่เหมือนศูนย์ของชุดย่อยนี้ มันเพิ่งเกิดขึ้นนั่น212 | 101 | 212คือองค์ประกอบศูนย์สำหรับเซตย่อย 3 คูณ 3 ตัวอย่างเช่น:

2 2 2   2 1 2   4 3 4    0 5 0    2 1 2    2 2 2
2 2 2 + 1 0 1 = 3 2 3 -> 5 2 5 -> 1 6 1 -> 2 2 2
2 2 2   2 1 2   4 3 4    0 5 0    2 1 2    2 2 2

นี่คือความท้าทายของคุณ: ได้รับแล้ว nค้นหาเอกลักษณ์องค์ประกอบของส่วนย่อยของnโดยnตาราง เอาท์พุทมันโดยการกำหนดสีที่ไม่ซ้ำกันที่มีความคมชัดเพียงพอที่คุณเลือกให้กับแต่ละ0, 1, 2, 3และส่งภาพ n โดย n รหัสของคุณจะต้องสามารถผลิตเคสขนาด 50 x 50 ได้ภายในไม่กี่นาทีบนพีซีที่ทันสมัย


ตัวอย่างเช่นองค์ประกอบข้อมูลเฉพาะตัว 500 โดย 500:

องค์ประกอบประจำตัว 500 ถึง 500

นี่คือสีฟ้า = 3, สีเขียว = 2, สีแดง = 1, สีขาว = 0 แต่คุณไม่จำเป็นต้องใช้ชุดรูปแบบสีนี้ในคำตอบของคุณ


2
คำเตือนต่อคู่แข่ง: ฉันอธิบายว่าโซลูชันนี้ไม่ใช่วิธีคำนวณ รหัสของคุณจะต้องสามารถสร้างเคส 50 ถึง 50 ในเวลาไม่ถึงนาทีดังนั้นการบังคับเดรัจฉานจึงเป็นไปไม่ได้ มีอัลกอริทึมสำหรับการแก้ปัญหานี้และฉันไม่ให้คุณ นั่นเป็นความตั้งใจ ฉันรู้สึกว่าความท้าทายที่มากเกินไปนำเสนอคุณด้วยอาหารก่อนเคี้ยว ฉันจะให้ 100 รางวัลกับคำตอบแรกที่ไม่ทำให้เกิดปัญหาเล็กน้อยกับ builtin (ดูที่คุณ Mathematica) ขึ้นอยู่กับดุลยพินิจของฉัน
orlp

2
ฉันคิดว่าภาพของตัวตน 500x500 น่าจะได้ประโยชน์จากการบอกว่าตัวเลขแต่ละสีตรงกับอะไร
xnor

อะไรคือ "ความเปรียบต่างที่เพียงพอ"?
Conor O'Brien

@ ConorO'Brien ชุดของสีใด ๆ ที่สามารถแยกแยะได้อย่างเพียงพอ ฉันสามารถทำให้มันเป็นเป้าหมาย 100% ด้วยการวัดสี แต่ฉันรู้สึกว่าเกินความจริง ฉันไม่สนใจว่าคุณใช้สีแดง, สีเหลือง, สีเขียว, สีเทาหรืออะไรก็ตามอย่าใช้สีเทา 4 เฉดที่อยู่ใน 1% ของแต่ละคน (เช่น # 000000, # 000001, # 000002, # 000003)
orlp

อะแฮ่มผมเชื่อว่าคำถามนี้คือตอนนี้มีสิทธิ์ได้รับเงินรางวัล ฉันจะได้รับโบนัส +100 ไหม? :)
จองฮวานมิน

คำตอบ:


2

อ็อกเทฟ120 120ไบต์

function a=W(a);while nnz(b=a>3);a+=conv2(b,[t=[0 1 0];!t;t],'same')-b*4;end;end;@(n)imagesc(W((x=ones(n)*6)-W(x)))

ขอบคุณJungHwan Min ที่ให้ลิงก์ไปยังเอกสารอ้างอิงในคำตอบวิชาคณิตศาสตร์ของเขา
ขอบคุณStewie Griffin ที่ช่วยฉันให้รอด 7 ไบต์[any(any(x)) -> nnz(x)]

ที่นี่สองฟังก์ชั่นการใช้งาน:

1. f: เพื่อความเสถียรของเมทริกซ์
2. ฟังก์ชันที่ไม่ระบุตัวตนที่รับnเป็นอินพุตและแสดงเมทริกซ์เอกลักษณ์

ลองใหม่อีกครั้ง! สำหรับการสร้างเมทริกซ์ 50 * 50

0.0844409 secondsเวลาที่ผ่านไปในการคำนวณเมทริกซ์:

คำอธิบาย:

พิจารณาฟังก์ชั่น f ที่ทำให้เมทริกซ์คงที่ซึ่งงานในการค้นหาตัวตนนั้นเป็นเรื่องง่าย

f(ones(n)*6 - f(ones(n)*6).

ที่ ones(n)*6หมายถึงเมทริกซ์ * n ของ 6

ดังนั้นสำหรับn=3:

M = [6 6 6
     6 6 6
     6 6 6];

ผลจะเป็นอย่างไร f(M-f(M))

สำหรับฟังก์ชั่นลดการสั่นไหว 2D ใช้เพื่อเพิ่มความเร็วในการทำงาน; ในการวนซ้ำแต่ละครั้งเราสร้างเมทริกซ์ไบนารีที่bมีขนาดเท่ากันของเมทริกซ์อินพุตและตั้งค่าเป็น 1 หากองค์ประกอบที่สอดคล้องกันของเมทริกซ์อินพุตคือ> 3 จากนั้นเราใช้การแปลง 2D เมทริกซ์ไบนารีกับมาสก์ต่อไปนี้

0 1 0
1 0 1
0 1 0

คิดเป็นสี่เพื่อนบ้านโดยตรง
ผลลัพธ์ของการบิดจะถูกเพิ่มเข้าไปในเมทริกซ์และ 4 เท่าของเมทริกซ์ไบนารีที่หักออกจากมัน

วนซ้ำอย่างต่อเนื่องจนกว่าองค์ประกอบทั้งหมดของเมทริกซ์คือ <= 3

เวอร์ชันที่ไม่ถูกปรับแต่ง :

function a=stabilize(a)
    mask = [t=[0 1 0];!t;t];
    while any(any(b=a>3))
        a+=conv2(b,mask,'same')-b*4;
    end
end
n= 50;
M = ones(n)*6;
result = stabilize(M-stabilize(M));
imagesc(result);

8

Mathematica, 177 157 135 133 ไบต์

Colorize[f=BlockMap[⌊{l={0,1,0},1-l,l}#/4⌋~Total~2+#[[2,2]]~Mod~4&,#~ArrayPad~1,{3,3},1]&~FixedPoint~#&;k=Table[6,#,#];f[k-f@k]]&

nใช้เวลาจำนวน เอาท์พุทเป็นทรายทรายเอกลักษณ์ 0 คือสีดำ 1 เป็นสีเทาอ่อน 2 คือสีม่วงแดงและ 3 คือสีฟ้าเทา

น่าเศร้าที่ Mathematica ไม่มี builtin สำหรับสิ่งนี้ ...

ใช้วิธีการที่ระบุไว้ในสกอตต์และเดวิด Corry Perkinson กระดาษ

ใช้เวลา 91.7 วินาทีในแล็ปท็อปอายุ 5 ปีของฉันในการคำนวณหา 50x50 identity sandpile ฉันมั่นใจว่าคอมพิวเตอร์เดสก์ท็อปสมัยใหม่ที่สมเหตุสมผลนั้นเร็วกว่า 50% (ฉันยังมีรหัสเร็วขึ้นในตอนท้าย)

คำอธิบาย

f= ...

กำหนดฟังก์ชั่นf(อินพุตเป็นเมทริกซ์ sandpile): ฟังก์ชันที่ ...

BlockMap[ ... ]~FixedPoint~#&

... ทำการBlockMapดำเนินการซ้ำจนกระทั่งเอาต์พุตไม่เปลี่ยนแปลง BlockMapการดำเนินการ: ...


#~ArrayPad~1

... pad อาร์เรย์อินพุตที่มีหนึ่งเลเยอร์ของ 0 ...

{3,3},1

... แบ่งเป็นเมทริกซ์ 3x3 โดยมี offset 1 ...

⌊{l={0,1,0},1-l,l}#/4⌋~Total~2+#[[2,2]]~Mod~4&

... และสำหรับแต่ละพาร์ติชันให้เพิ่มจำนวนเม็ดทรายที่ตกลงบนเซลล์กลางและค่าเซลล์กลาง mod 4

เช่นผลลัพธ์ของการfเป็นรุ่นที่มีเสถียรภาพของการป้อนข้อมูล


k=Table[6,#,#]

กำหนดkเป็นnโดยnอาร์เรย์ของ 6s

f[k-f@k]]

คำนวณ f (k - f (k))

Colorize[ ... ]

ใช้สีกับผลลัพธ์

รุ่นที่เร็วกว่า (142 ไบต์)

Colorize[r=RotateLeft;a=ArrayPad;f=a[b=#~a~1;b+r[g=⌊b/4⌋,s={0,1}]+g~r~-s+r[g,1-s]+r[g,s-1]-4g,-1]&~FixedPoint~#&;k=Table[6,#,#];f[k-f@k]]&

รหัสเดียวกัน BlockMapแต่ใช้ตัวในการหมุนรายการแทน คำนวณ n = 50 ใน 4.0 วินาทีบนแล็ปท็อปของฉัน


พิจารณาว่าคุณทำตามจิตวิญญาณของการ จำกัด เวลา (ใช้อัลกอริทึมจริงแทนที่จะใช้กำลังดุร้าย) และเป็นไปได้มากที่คอมพิวเตอร์เดสก์ท็อปที่ทรงพลังเร็วกว่า 50% ฉันจะอนุญาต เนื่องจากมันใช้อัลกอริธึมที่แท้จริงโดยไม่มีบิวด์อินเล็กน้อยจึงมีคุณสมบัติสำหรับโบนัส +100 คุณจะต้องรอเพราะฉันยังไม่สามารถเริ่มเงินรางวัลได้
orlp

การที่ใช้ภาษา Python (ภาษาที่มีชื่อเสียงช้า) ใช้เวลาประมาณ ~ 2 วินาทีสำหรับ n = 50 บางทีคุณอาจเพิ่มความเร็วได้บ้างไหม?
orlp

@ หรือทำเสร็จแล้ว แต่มันยาวเกินกว่ารหัสเดิม ฉันควรจะให้คำตอบหลักของฉันเป็นเวอร์ชันที่เร็วขึ้นหรือฉันจะวางให้จบ
JungHwan Min

ฉันคิดว่าอย่างนี้แหละ
orlp

0

Python 3 + Numpy + PIL, 385 370 364 ไบต์

import numpy as q,PIL.Image as w
n=int(input())
z=n,n
def r(p):
 while len(p[p>3]):
  for x,y in q.ndindex(z):
   if p[x,y]>3:
    p[x,y]-=4;p[x-1,y]+=x>0;p[x,y-1]+=y>0
    if~-n>x:p[x+1,y]+=1
    if~-n>y:p[x,y+1]+=1
s=q.full(z,6)
t=s.copy()
r(t)
i=s-t
r(i)
w.fromarray(q.uint8(q.array(q.vectorize(lambda x:[x//1*65]*3,otypes=[object])(i).tolist()))).save('i.png')

ใช้อินพุตบน STDIN i.pngขาออกภาพเป็นขาวดำเพื่อ สีดำสอดคล้องกับ 0, สีเทาเข้มถึง 1, สีเทาอ่อนถึง 2 และสีขาวเป็น 0

ใช้สูตรI = R(S - R(S))โดยที่Iองค์ประกอบตัวตนSคือเมทริกซ์ที่เต็มไปด้วยหกและRเป็นฟังก์ชันการลด

ฉันอาจบันทึกบางไบต์ด้วยการเปลี่ยนไปใช้ Python 2 และทำfrom numpy import*แต่ (1) ฉันไม่ได้ติดตั้ง Numpy ใน Python 2 และ (2) โปรแกรมไม่ได้หยุดfrom numpy import*ทำงาน

Ungolfed:

import numpy as np
from PIL import Image

# Compute the identity element

n = int(input('Size of the sandpile: '))

def reduce_pile(sandpile):
  while any(element >= 4 for element in np.nditer(sandpile)):
    for x, y in np.ndindex((n, n)):
      if sandpile[x, y] >= 4:
        sandpile[x, y] -= 4
        if x > 0: sandpile[x - 1, y] += 1
        if y > 0: sandpile[x, y - 1] += 1
        if x < n - 1: sandpile[x + 1, y] += 1
        if y < n - 1: sandpile[x, y + 1] += 1

s = np.full((n, n), 6, dtype=np.int32)
s_prime = np.copy(s)

reduce_pile(s_prime)

identity = s - s_prime
reduce_pile(identity)

# Output it to identity.png as an image

colours = [[255, 255, 255], [255, 0, 0], [0, 255, 0], [0, 0, 255]]
img_array = np.vectorize(lambda x: colours[x], otypes=[object])(identity)
img_array = np.array(img_array.tolist(), dtype=np.uint8)

img = Image.fromarray(img_array)
img.save('identity.png')

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