Магнітні скульптури


14

Це слабке продовження мого попереднього завдання зі створення графіків .

Фон

Ексцентричний художник найняв вас на оцінку структурної цілісності його скульптур. Він творить свої твори мистецтва, беручи купу магнітоподібних кубиків і скидаючи їх по черзі у величезну купу. Для кращого аналізу його методу ми використовуємо наступну двовимірну модель. Ми починаємо з порожнього поверху і опускаємо магніт #на будь-яку цілу координату, скажімо 0:

       |
       v
       #
===============
       0

Якщо впаде інший магніт 0, він закінчується поверх попереднього:

       |
       v
       #
       #
===============
       0

Тепер давайте кинемо ще один магніт на 0, а потім один на 1:

        |
       #v
       ##
       #
===============
       0

Як видно вище, падаючий магніт прилипає до другого магніту, який він пропускає (перший просто уповільнює його). Другий магніт не повинен знаходитися безпосередньо під першим, а магніт з обох сторін все ще вважається одним магнітом:

      #   #
      ##|##
      # v #
      ### #
      #   #
===============
       0

Художники хочуть, щоб ви обчислили максимальну вертикальну щілину в кінцевій скульптурі, тобто максимальну кількість порожніх проміжків між двома магнітами на одному стовпчику, або магнітом і землею під ним. На наведеному малюнку це число було б 3 (у стовпці 2).

Вхідні дані

Список цілих чисел, що представляють координати, куди художник скидає свої магніти, читається зліва направо. Ви можете припустити, що координати задовольняють -1024 <= i < 1024і що довжина списку становить максимум 1024, якщо це допомагає.

Вихідні дані

Максимальний вертикальний зазор у фінальній скульптурі. Порожня скульптура має прогалини -1, і цю справу треба включити, оскільки наш скульптор - дадаїст.

Додаткові правила

Ви можете надати функцію або повну програму. Виграє найкоротший байт, а стандартні лазівки заборонені. Код з поясненнями є кращим.

Тестові справи

[] -> -1
[0,2,1] -> 0
[0,0,0,0,0,1,-1] -> 3
[0,0,0,0,0,1,1,1,2] -> 4
[1,1,2,2,2,2,2,2,1] -> 2
[1,1,2,2,2,2,2,2,1,0,1,0] -> 2
[1,2,1,2,1,2,1,2,2,2,2,1,0] -> 3
[-1,-1,-1,1,1,1,0] -> 1
[-1,-1,-1,-1,2,2,1,1,2,2,2,1,0] -> 2
[-2,-2,-2,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,4,4,5,5,5,6] -> 6

Відповіді:


1

Діялог APL, 73 70 символів

{y←⍬⋄⌈/¯1,,¯1-2-/0,x⊢⌸{y,←⌈/(1+y/⍨0=⍵),Y⊃⍨2⊃⍒Y←1 1,∪y/⍨1=⍵}¨|x-¯1↓¨,\x←⍵}

{y←⍬⋄¯1⌈⌈/,¯1-2-/¯1,⍵⊢⌸{y,←⌈/(1+y/⍨0=⍵),⊃1↓{⍵[⍒⍵]}∪y/⍨1=⍵}¨|⍵-¯1↓¨,\⍵}

First statement:
       y←⍬  initialize semi-global variable y with an empty vector
Second statement, from right to left:
         ⍵  the vector of x coordinates
       ,\⍵  concat-scan: all prefixes of ⍵ of length 1, 2, ..., ≢⍵
   ¯1↓¨,\⍵  drop the last element of each prefix, lengths are 0, 1, ..., (≢⍵)-1
|⍵-¯1↓¨,\⍵  for each x: magnitudes of differences between x and its predecessors
 {...}¨...  execute the code in parens for each item of the argument
         ⍵  is now a single vector of differences from those described above
       1=⍵  boolean mask, where are our neighbouring xs?
    y/⍨1=⍵  select the ys corresponding to our neighbouring xs
   ∪y/⍨1=⍵  unique ys
   {⍵[⍒⍵]}  sort descending
       ⊃1↓  first of one-drop, i.e. get the second element if it exists, otherwise 0
       0=⍵  which previous xs are the same as our x?
  1+y/⍨0=⍵  select the corresponding ys and add 1 to them
        ⌈/  maximum of all the ys described so far
       y,←  append to the semi-global y
            the result from {} will be identical to y
  ⍵⊢⌸{...}  a matrix of ys, grouped in rows by x (which is now in ⍵) and zero-padded
       ¯1,  prepend ¯1 to the left of each row
       2-/  differences between consecutive horizontal elements, result is a matrix
       ¯1-  negative one minus each element of the matrix
         ,  ravel the matrix (linearize it to a vector)
        ⌈/  maximum; if the vector is empty, return ¯1.8e308, a very small number
     ¯1⌈⌈/  greater of ¯1 and the ⌈/  to avoid the very small number

Примітка. Це 122 байти завдовжки (виклик знаходиться в байтах), припускаючи UTF-8.
MtnViewMark


Я дуже співчуваю: мене часто намагалися використовувати символи, що не належать до ASCII, в моєму гольф-Haskell. З тих пір я дуже пам’ятаю, якщо Q визначає підрахунок символів чи байтів.
MtnViewMark

@MtnViewMark Оцінка за байтами не означає оцінка балів UTF-8. Якщо це зробити для APL, це карається за те, що вона занадто стара, щоб визнати ASCII важливим стандартом. Набір символів APL легко вписується в однобайтову кодову сторінку, і ця кодова сторінка існує . Тож використання цієї кодової сторінки як кодування кожного символу є байтом. З іншого боку, якщо ви використовуєте символи, що не належать до ASCII, у Haskell, вам доведеться використовувати кодування, яке містить як ASCII, так і не ASCII символи - і це зазвичай UTF-8.
Мартін Ендер

@ngn - прочитавши зараз більшість мета-повідомлень з цього приводу, здається, що речі, на жаль, все ще каламутні. Однак, можливо, було б найкраще, коли виклик оцінюється в байтах, оцінювати APL в байтах, але десь згадайте про використане кодування.
MtnViewMark

4

Haskell - 217 185 182 байт

import Data.List
r g n m|m==n=max(head(g m)+1)((reverse.(0:).nub.sort$g(m-1)++g(m+1))!!1):g m|1<3=g m
j x=(-1)-minimum(0:(map(foldl r(\_->[0])x)[-1024..1024]>>=(tail>>=zipWith(-))))

Використання:

j [1,2,1,2,1,2,1,2,2,2,2,1,0]

Ця функція створює іншу функцію, яка повертає список y-положень магніту для заданої позиції x. З його допомогою він обчислює прогалини для всіх x-позицій -1024 .. 1024 і приймає максимум (Редагувати: зараз я беру мінімум, тому що пропуски від’ємні: чим менше число, тим більший розрив).


Розумний підхід! Сподіваюсь, ви не заперечуєте, що я трохи заграв у нього.
MtnViewMark

@MtnViewMark: Зовсім не. Я знайшов ще 3 байта для збереження: чи не , йти з негативними числами і прийняти . flip-minimum
німі

У моєму репортажі ви можете знайти цей код, 42997-Magnetic.hs, який також включає тестовий джгут для тестових кейсів та візуалізатор, що демонструє скульптури.
MtnViewMark

3

Javascript, 201 193

F=P=>{m=[];for(p of P){s=2;c=m[p]=m[p]||[];for(i=1e4;~i&&s;i--){if((m[p-1]||[])[i]||(m[p+1]||[])[i])s--;if(c[i-1]) s=0}c[++i]=1}g=-1;m.map(c=>{ d=0;for(i in c){g=i-d>g?i-d:g;d=++i} });return g}

F ([1,1,2,2,2,2,2,2,1]) === 2

Або читана версія

F=P=>{
  m=[];  // magnet positions
  for(p of P){ // every dropped magnet
    s=2; // initial speed
    c=m[p]=m[p]||[]; // column where magnet is dropping
    for(i=1e4;~i&&s;i--){ // continue until at floor or zero speed
      if((m[p-1]||[])[i]||(m[p+1]||[])[i])s--;  // magnet on either side, decrease speed
      if(c[i-1]) s=0; // magnet is directly below
    }
    c[++i]=1;
  }
  g=-1; // maximum gap
  m.map(c=>{ 
          d=0;for(i in c){g=i-d>g?i-d:g;d=++i;} 
       });
  return g;
};

2

Пітон 2.7, 327

from itertools import * 
s=input()
if s:m=min(s);l=[[] for _ in range(max(s)-m+3)]
for t in s:
    i=t-m+1;r=l[i];c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:];j=len(c)-c.index(1)-1-len(r) if any(c) else 0;l[i]=r+[0]*j+[1]
print -1 if not s else max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

Перед білим космічним гольфом це виглядає приблизно так:

from itertools import * 
s=input()
if s:
    m=min(s)
    l=[[] for _ in range(max(s)-m+3)]
for t in s:
    i=t-m+1;r=l[i]
    c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:]
    j=len(c)-c.index(1)-1-len(r) if any(c) else 0
    l[i]=r+[0]*j+[1]
print -1 if not s else max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

Ось пояснення більш складних ліній, переважно для моєї користі.

l=[[] for _ in range(max(s)-m+3)] 

Це створює масив порожніх списків довжиною max (краплі) -min (краплі) +1 плюс заповнювач місця з обох сторін. Я завжди хочу написати [[]] * K, щоб побудувати масив порожніх списків, але це робить K вказівники на той самий порожній список.

c=[x or y for x,y in izip_longest(l[i-1],l[i+1])][::-1][1:] 

Функція izip_logest з itertools схожа на zip, але заповнює коротший список None, щоб зібрати списки разом. Нарізка [:: - 1] повертає список 0 і 1 до порівняння "або". Список обернено для того, щоб використовувати метод індексу в наступному рядку, який знаходить перший екземпляр елемента. Оскільки в останньому елементі непорожнього стовпця повинно бути 1, це перший елемент у зворотному списку і ігнорується через фрагмент [1:].

j=len(c)-c.index(1)-1-len(r) if any(c) else 0 
l[i]=r+[0]*j+[1]

Спочатку обчисліть різницю між довжиною стовпця i та позицією другого 1 у сусідніх стовпцях. Якщо різниця позитивна, додайте, що до стовпця i додається багато нулів, перш ніж додавати 1. Порожній список є будь-яким непозитивним числом разів [0].

max([len(list(q)) if b==0 else 0 for k in l for b,q in groupby(k)])

Функціональна група за допомогою itertools розбиває список на послідовності послідовних елементів. Цей рядок знаходить максимум довжин усіх підрядів нулів у всіх стовпцях. Кожне підпорядкування q потрібно подавати до списку, оскільки groupby повертає генератор (як і всі функції itertools), який, природно, не підтримує метод len.


1

Java - 281 байт

Досить прямо вперед.

Спочатку він будує скульптуру в масиві

Тоді він знаходить найбільшу прогалину.

int a(int[]b){
        int[][]d=new int[9999][9999];
        int g,r,t,y=-1;
        for(int c:b){
            c+=5000;
            g=0;
            for(r=9998;r>=0;r--){
                if(r==0||d[c][r-1]==1){d[c][r]=1;break;}
                if((d[c-1][r]==1||d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}
            }
        }
        for(int[] k:d){
            t=0;
            for(int i:k){
                if(i==0)t++;
                else{if(t>y)y=t;t=0;}
            }
        }
        return y;
    }

маленький -

int a(int[]b){int[][]d=new int[9999][9999];int g,r,t,y=-1;for(int c:b){c+=5000;g=0;for(r=9998;r>=0;r--){if(r==0||d[c][r-1]==1){d[c][r]=1;break;}if((d[c-1][r]==1||d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}}}for(int[] k:d){t=0;for(int i:k){if(i==0)t++;else{if(t>y)y=t;t=0;}}}return y;}

Ви можете зберегти байт, замінивши перший ||на |. Також повернення yзамість друку заощаджує 9 байт.
Ypnypn

@Ypnypn, Дякую! До речі, ваше перше твердження, здається, кидає виняток ArrayIndexOutOfBounds (-1). (У мене немає великого досвіду роботи з побітними операторами)
Stretch Maniac

Це було близько 1,5 років, але ви можете грати в гольф це ще небагато: ( 272 байт ): int a(int[]b){int z=9999,d[][]=new int[z][z],g,r,t,y=-1;for(int c:b){c+=z/2;g=0;for(r=z;--r>-2;){if(r==0||d[c][r-1]==1){d[c][r]=1;break;}if((d[c-1][r]==1|d[c+1][r]==1)&&++g==2){d[c][r]=1;break;}}}for(int[]k:d){t=0;for(int i:k){if(i==0)t++;else{if(t>y)y=t;t=0;}}}return y;}. Короткий зміст змін: z=9999додано та використано; intі int[][]ініціалізація поля була об'єднана в одне ціле; другий ||замінюється на |; for(r=9998;r>=0;r--)було змінено наfor(r=z;--r>-2;)
Кевін Круїйсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.