Знайдіть особу пісочника


18

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


Абелевий пісковик розміром n на n - це сітка, що містить числа 0, 1, 2 і 3 (що представляє кількість зерен піску). Додавання двох пісковиків працює, спочатку додаючи елемент за елементом, а потім підсипаючи будь-який елемент, що перевищує 3. Порядок, в якому ви пересипаєте, не має значення, кінцевий результат такий же. Коли клітина перекидається, її кількість зменшується на 4, а кожен з її прямих сусідів збільшується на 1. Це може спричинити ланцюгову реакцію. Якщо клітина знаходиться на краю сітки, будь-які зерна, які випадають з сітки під час збивання, зникають.

Наприклад, я додаю два пісковики 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 пісковиків. Цей підмножина містить будь-який пісковик, який ви можете отримати, додавши довільний пісковик до всіх-3s n на n sandpile. Наприклад, трохи вище ми побачили, що 212 | 101 | 212є в підмножині, тому що ми отримали це, додавши щось до все-3 пісочника.

Тепер цей підмножина має цікавий елемент: елемент ідентичності . Якщо взяти цей елемент і додати його до будь-якого іншого елемента в підмножині , сума не зміниться. Іншими словами, цей пісковик діє як нуль цього підмножини. Так буває, що 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

Тепер це ваша задача: з огляду на п , знайти одиничний елемент підмножини п по п сітці . Виведіть його, призначивши унікальний колір з достатнім контрастом на ваш вибір кожному з них 0, 1, 2, 3та виведіть зображення n на n. Ваш код повинен бути спроможним створити корпус розміром 50 на 50 на розумному сучасному ПК.


Наприклад, елемент ідентичності 500 на 500:

500 на 500 елемент ідентичності

Тут синій = 3, зелений = 2, червоний = 1, білий = 0. Але вам не потрібно використовувати цю колірну гаму у своїй відповіді.


2
Слово попередження для конкурентів: Я описав, що таке рішення, а не як його обчислити. Ваш код повинен мати можливість справляти справу 50 на 50 за менше хвилини, тому грубе форсування не є можливим. Існують алгоритми вирішення цього питання, і я вам їх не даю. Це навмисно. Я відчуваю, що занадто багато викликів ставить перед вами попередньо пережована їжа. Я дам +100 щедрості до першої відповіді, яка не перешкоджає проблемі з вбудованим (дивлячись на вас, Mathematica), на мій розсуд.
orlp

2
Я думаю, що зображення особи 500x500 виграло б, коли сказати, якому номеру відповідає кожен колір.
xnor

Що являє собою "достатній контраст"?
Conor O'Brien

@ ConorO'Brien Будь-який набір кольорів, які є достатньо помітними. Я міг би зробити це на 100% об'єктивним за допомогою кольорової міри, але відчуваю, що це надмірно. Мені все одно, якщо ви використовуєте червоний, жовтий, зелений, відтінки сірого чи будь-що інше, просто не використовуйте 4 відтінки сірого, які знаходяться в межах 1% від одного (наприклад, # 000000, # 000001, # 000002, # 000003).
orlp

ах, я вважаю, що це питання зараз підходить для щедрості. Чи можу я отримати бонус +100? :)
JungHwan Min

Відповіді:


2

Октава, 120 113 байт

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 за те, що він надав посилання на довідковий документ у своїй відповіді Mathematica.
Завдяки Стюі Гріффін врятував мені 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

представляючи чотирьох прямих сусідів.
Результат згортки додається до матриці і від неї віднімається вдвічі більша матриця.

Цикл продовжувався, поки весь елемент матриці не буде <= 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

Математика, 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 не має вбудованого для цього ...

Використовується алгоритм, зазначений у статті Скотта Коррі та Девіда Перкінсона .

На мій 5-річний ноутбук потрібно 91,7 секунди, щоб обчислити сандфіл 50x50. Я впевнений, що розумний сучасний настільний комп'ютер швидше на 50%. (У мене також є кінець швидшого коду).

Пояснення

f= ...

Визначте функцію f(вхід є матрицею пісковика): функція, яка ...

BlockMap[ ... ]~FixedPoint~#&

... повторює BlockMapоперацію, поки вихід не зміниться. BlockMapоперація: ...


#~ArrayPad~1

... прокладіть вхідний масив одним шаром 0 ...

{3,3},1

... розділіть його на 3x3 матриці зі зміщенням 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 (горезвісно повільна мова) займає лише ~ 2s для n = 50. Може, ви можете трохи прискорити це?
orlp

@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) у мене на Python 2 та (2) програма не встановлена, Numpy не закінчується from numpy import*.

Безголовки:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.