Побудуйте стійку цегляну стіну


39

Цегляна стіна - це прямокутник, виготовлений з горизонтальної цегли 1 на n, складеної в рядки. Ось стіна висотою 4 та шириною 8, розміри цегли - справа.

[______][______]    4 4
[__][____][__][]    2 3 2 1
[][______][____]    1 4 3
[____][______][]    3 4 1

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

[______][______]    
[__][____)(__][]
[][______)(____]
[____][______][]

Але тріщини, що межують з цеглою розміром 1 праворуч, не утворюють несправності, оскільки вони розділені рядом.

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

Вхідні дані

Непорожній список розмірів цегли (додатні цифри) та висоти, щонайменше 2. Цей список може бути відсортований за бажанням. Ви також можете взяти кількість цегли кожного розміру.

Вихідні дані

Зображення стійкої прямокутної стіни необхідної висоти, яка використовує всі задані цегли. Роздрукуйте його або поверніть у вигляді рядка з новими рядками.

Намалюйте цеглу розміром n у вигляді 2n символів, підкресливши, оточені дужками.

1: []
2: [__]
3: [____]
4: [______]
...

Гарантія матиме хоча б одне рішення. Якщо їх декілька, вам слід намалювати лише одну стіну.

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

Тестові приклади:

Є декілька рішень, тому результати можуть бути різними.

>> [1, 1, 2, 2], 2
[][__]
[__][]

>> [1, 1, 1, 2, 2, 2, 2, 3], 2
[__][____][__]
[][__][][__][]

>> [1, 1, 2, 2, 3, 3, 3, 3], 3
[][__][____]
[__][____][]
[____][____]

>> [1, 2, 3, 4, 5, 6, 7, 8, 9], 5
[][______________]
[__][____________]
[________________]
[____][__________]
[______][________]

>> [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 5
[][__][__]
[__][__][]
[][__][__]
[__][__][]
[][__][__]

чому ви вирішили зробити цегли шириною 2n замість n> 1 символів шириною?
Спарр

2
Блоки символів @Sparr 1 на 2 виглядають приблизно квадратними. Я намагався вимагати n>1і мені не подобалося, як це обмежувало тестові випадки. Також, мабуть, є прецедент .
xnor

Я не маю на увазі 2n з n> 1. Я маю на увазі n з n> 1.
Спарр

Відповіді:


20

Перл, 166 170 194

Ідеальне завдання для мови, створеного Ларрі Уоллом.

#!perl -pa
$_=(1x($x=2/($y=pop@F)*map{1..$_}@F)."
")x$y;sub
f{my$l=$_;$-|=!@_;for$=(@_){$Z=__
x~-$=;$f=0;s/(11){$=}/[$Z]/&!/\]..{$x}\[/s&&f(grep$=ne$_||$f++,@_);$-or$_=$l}}f@F

Груба сила, але досить швидко на тестових випадках (<1 с). Використання:

$ perl ~/wall.pl <<<"1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 5"
[][__][__]
[__][__][]
[][__][__]
[__][__][]
[][__][__]

Випробуй мене .


9
Ха, мені цікаво, чи колись Ларрі Уолл думав, що люди будуть користуватися такою мовою ... :)
crazyhatfish

12

CJam, 94 92 82 байт

Це версія на 92 байти. 82-байтна версія наступна.

l~1$,:L,:)m*{1bL=},\e!\m*{~W<{/(\e_}%}%{::+)-!},{{_,,\f<1fb}%2ew{:&,(},!}={{(2*'_*'[\']}/N}/

Це розділяє цегли всіляко і бере лише той, що є дійсним. На сьогоднішній день досить груба сила, але все ще працює останній тестовий випадок приблизно за 10 секунд на Java-перекладачі на моїй машині.

Пояснення :

Код розділений на 5 частин:

1) Враховуючи масив довжини L, як усі ми можемо розділити його на Hчастини.

l~1$,:L,:)m*{1bL=},
l~                     e# Read the input as string and evaluate it.
  `$,:L                e# Copy the array and take its length. Store that in L
       ,:)             e# Get an array of 1 to L
          m*           e# Cartesian power of array 1 to L of size H (height of wall)
            {1bL=},    e# Take only those parts whose sum is L

Після цього у нас є всі можливі способи поділу нашого вхідного масиву на шари цегли H.

2) Отримайте всі перестановки вхідного масиву, а потім отримайте всі розділи для всіх перестановок

\e!\m*{~W<{/(\e_}%}%
\e!                    e# Put the input array on top of stack and get all its permutations
   \m*                 e# Put the all possible partition array on top and to cartesian
                       e# product of the two permutations. At this point, every
                       e# permutation of the input array is linked up with every
                       e# permutation of splitting L sized array into H parts
      {           }%   e# Run each permutation pair through this
       ~W<             e# Unwrap and remove the last part from the partition permutation
          {     }%     e# For each part of parts permutation array
           /           e# Split the input array permutation into size of that part
            (\         e# Take out the first part and put the rest of the parts on top
              e_       e# Flatten the rest of the parts so that in next loop, they can be
                       e# split into next part length

Після цього у нас є всі можливі схеми введення цегли в Hшари цегляної стіни.

3) Відфільтруйте лише ті схеми, довжина яких у цегли однакова

{::+)-!},
{      },              e# Filter all brick layouts on this condition
 ::+                   e# Add up brick sizes in each layer
    )-!                e# This checks if the array contains all same lengths.

Після закінчення цього фільтра всі залишилися макети стануть ідеальними прямокутниками.

4) Вийміть перший цегляний макет, який відповідає критеріям стійкості

{{_,,\f<1fb}%2ew{:&,(},!}=
{                       }=   e# Choose the first array element that leaves truthy on stack
 {         }%                e# For each brick layer
  _,,                        e# Create an array of 0 to layer length - 1
     \f<                     e# Get all sublists starting at 0 and ending at 0
                             e# through length - 1
        1fb                  e# Get sum of each sub list. This gives us the cumulative
                             e# length of each brick crack except for the last one
           2ew               e# Pair up crack lengths for every adjacent layer
              {    },        e# Filter layer pairs
               :&            e# See if any cumulative crack length is same in any two
                             e# adjacent layers. This means that the layout is unstable
                 ,(          e# make sure that length of union'd crack lengths is greater
                             e# than 1. 1 because 0 will always be there.
                     !       e# If any layer is filtered through this filter,
                             e# it means that the layer is unstable. Thus negation

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

5) Роздрукуйте макет

{{(2*'_*'[\']}/N}/
{               }/           e# For each brick layer
 {           }/              e# For each brick
  (2*'_*                     e# Get the (brick size - 1) * 2 underscores
        '[\']                e# Surround with []
               N             e# Newline after each layer

Спробуйте його онлайн тут


82 байти

l~:H;{e_mrH({H-X$,+(mr)/(\e_}%_::+)-X${_,,\f<1fb}%2ew{:&,(},+,}g{{(2*'_*'[\']}/N}/

Це майже схоже на версію з 92 байтами, за винятком того, що вона має відтінок випадковості. Якщо ви прочитали пояснення до версії 92 байтів, то у версії з 82 байтами частини 3, 4 і 5 деталі абсолютно однакові, тоді як замість повторення всіх перестановок з частин 1 і 2 ця версія просто випадковим чином генерує одну з перестановка за один раз, тестує її за допомогою частин 3 і 4, а потім знову запускає процес, якщо тести частин 3 і 4 провалюються.

Це дуже швидко друкує результати для перших 3 тестових випадків. Тестовий випадок висота = 5 ще повинен дати вихід на моєму комп’ютері.

Пояснення різниці

l~:H;{e_mrH({H-X$,+(mr)/(\e_}%_::+)-X${_,,\f<1fb}%2ew{:&,(},+,}g
l~:H;                           e# Eval the input and store the height in H
     {   ...   }g               e# A do-while loop to iterate until a solution is found
      e_mr                      e# Flatten the array and shuffle it.
          H({               }%  e# This is the random partition generation loop
                                e# Run the loop height - 1 times to get height parts
             H-X$,+(            e# While generating a random size of this partition, we
                                e# have to make sure that the remaining parts get at least
                                e# 1 brick. Thus, this calculation
                    mr)         e# Get a random size. Make sure its at least 1
                       /(\e_    e# Similar to 92's part 2. Split, pop, swap and flatten

_::+)-                          e# 92's part 3. Copy and see if all elements are same
      X${_,,\f<1fb}%2ew{:&,(},  e# 92's part 4. Copy and see if layers are stable
+,                              e# Both part 3 and 4 return empty array if
                                e# the layout is desirable. join the two arrays and
                                e# take length. If length is 0, stop the do-while

Ідею для цієї версії дали випадкові (Get it?)

Спробуйте це в Інтернеті


9

Python 2, 680 670 660 байт

Я не знаю, чому я наполягаю на тому, щоб мати ці супердовгі "гольфи" ... але все одно, ось ви.

M,L,R,N=map,len,range,None
exec"J=@:M(''.join,x);B=@:'['+'_'*2*~-x+']';K=@:M(B,x);W=@:J(M(K,x));C=@:set(M(sum,[x[:i]for i in R(L(x))]))-{0};T=@,w:w[x:]+w[:x]\ndef F(i):f=filter(@:i[x-1]&i[x],R(1,L(i)));return f and f[0]".replace('@','lambda x')
def P(e,x,i,w,h):
 for j in[-~_%h for _ in R(i-1,h+i-2)]:
    for s in R(w):
     if not e&C(T(s,x[j])):return j,s
 return N,N
def b(l,h):
 w,d=[[]for _ in R(h)],2*sum(l)/h
 for _ in l[::-1]:q=M(L,W(w));w[[q.index(i)for i in sorted(q)if i+L(B(_))<=d][-1]]+=_,
 g=M(C,w);i=F(g)
 while i:
    e=g[i-1];j,s=P(e,w,i,d,h)
    if j!=N:w[j]=T(s,w[j]);w[i],w[j]=w[j],w[i];g=M(C,w);i=F(g)
    else:b(T(-1,l),h);return
 print'\n'.join(W(w))

Для цього потрібен вихід у відсортованому порядку зростання та викликається через b(brick_sizes, height).

Тестові приклади:

>>> tests = [([1, 1, 2, 2], 2),([1, 1, 1, 2, 2, 2, 2, 3], 2), ([1, 1, 2, 2, 3, 3, 3, 3], 3), ([1, 2, 3, 4, 5, 6, 7, 8, 9], 5), ([1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 5)]
>>> for t in tests:
...     b(*t); print
... 
[__][]
[][__]

[____][__][__]
[][][__][__][]

[____][____]
[__][__][][]
[____][____]

[________________]
[______________][]
[____________][__]
[__________][____]
[________][______]

[__][__][]
[][__][__]
[__][__][]
[][__][__]
[__][__][]

Це працює так:

  1. Призначте цегли (найдовший-> найкоротший) шарам, намагаючись заповнити кожен шар, перш ніж перейти до наступного.
  2. Всякий раз, коли сусідні шари нестабільні, намагайтеся поміняти шари та переміщувати цеглу, поки не знайдете щось, що працює.
  3. Якщо нічого не працює, перемістіть найдовшу цеглу на передню частину списку розмірів і повторіть повтор.

1
Можливо, ви можете скинути це continueз кінця. Також return(N,N)не знадобляться дужки.
PurkkaKoodari

хороший дзвінок - це continueбула реліквія з попередньої версії.
серперцивал

1
Неможливо його запустити, у вас є стороння дужка Wі вам Tпередається додатковий аргумент.
crazyhatfish

ой, дякую! фіксований.
sirpercival

5

Haskell, 262 байти

import Data.List
c=concat
n=init.scanl1(+)
1%l=[[[l]]]
n%l=[map(h:)(c$(n-1)%t)|(h,t)<-map(`splitAt`l)[1..length l]]
v[x]=1<2
v(x:y:z)=sum x==sum y&&n x==n x\\n y&&v(y:z)
l#n=unlines$map(>>=(\b->'[':replicate(2*b-2)'_'++"]"))$head$filter v$c.(n%)=<<permutations l

Приклад використання:

*Main> putStr $  [1, 2, 3, 4, 5, 6, 7, 8, 9] # 5
[______][________]
[__________][____]
[____________][__]
[][______________]
[________________]

*Main> putStr $ [1, 1, 2, 2, 3, 3, 3, 3] # 3
[____][____]
[__][__][][]
[____][____]

Як це працює: основна функція #бере список l(список цеглин) та число h(висота) та розбиває всі перестановки lна hпідсписи на всі можливі позиції (через функцію %, наприклад 2%[1,2,3,4]-> [ [[1],[2,3]] , [[1,2],[3]] , [[1,2,3],[]] ]). Він зберігає ті, де два послідовних елементи мають однакову суму (тобто однакову довжину в цеглинах), а списки підсумкових даних не мають загальних елементів (тобто тріщини не вирівнюються, функціонують v). Візьміть перший список, який підходить, і побудуйте рядок з цегли.


4

Пітон 2, 528 , 417 , 393 , 381

Дуже довге, грубе рішення. Це працює, але це стосується цього, Всесвіт може закінчитися, перш ніж отримати результат для останнього тестового випадку.

exec u"from itertools import*;m=map;g=@w,n:([[w]],[[w[:i]]+s#i?range(1,len(w))#s?g(w[i:],n-1)])[n>1];r=@x:set(m(sum,[x[:i]#i?range(1,len(x))]));f=@w:1-all(m(@(x,y):not x&y,zip(m(r,w[:-1]),m(r,w[1:]))));a=@s,h:['\\n'.join([''.join(['[%s]'%(' '*(s-1)*2)#s?r])#r?o])#p?permutations(s)#o?g(p,h)if len(set([sum(r)#r?o]))<2 and~-f(o)][0]".translate({64:u"lambda ",35:u" for ",63:u" in "})

a - основна функція:

>> a([1, 1, 2, 2], 2)
'[][  ]\n[  ][]'

Ви можете зберегти 4 байти, змінивши імпорт from itertools import*та відхилившись itertools.від permutationsдзвінка. Крім того, ifs в кінці можна змінити на if all(x==w[0] for x in w)and~-f(o):return..., щоб зберегти 13 байт.
PurkkaKoodari

Крім того, не fзавжди повертається на першу ітерацію? Це дивно виглядає. Це або помилка, або величезна можливість для гольфу.
PurkkaKoodari

У вас є тонна сторонніх просторів, які можна видалити - до або після котирування / батьків / дужки, оточуючих оператора тощо. Ви також призначаєте t=0двічі r(); ви можете перетворити цю функцію map(sum,[x[:i] for i in range(len(x))])як однолінійний (підходить для лямбда-зингу, якщо хочете). Використання isdisjoint та встановлення in f()значно зменшить його (також f()наразі повертається лише після одного тесту, виявлено помилку чи ні). Особисто я б переписав f()як return not all(map(isdisjoint,map(set,map(r,w[:-1])),map(set,map(r,w[1:]))))щось подібне.
sirpercival

@ Pietu1998 О так, пропустив пробіл. Дякую за поради, хлопці, я вражений, що ви можете помітити ці речі.
crazyhatfish

сміюся занадто погано, я ненавиджу такі коди, де "Всесвіт може закінчитися, перш ніж отримати результат", але це найкоротший байт cotest що ще робити xD
Abr001am

3

JavaScript (ES6) 222 232 265 279 319

Ще треба пограти в гольф. Цей знайде всі рішення, вивести лише останні знайдені, і це досить швидко.

Запустіть фрагмент у Firefox для тестування

f=(n,h,b=[],s=0)=>
  (R=(z,l,p,k,t)=>
    z?b.map((v,a)=>
      v&&k.indexOf(v=t+a)<0&v<=s&&(
        --b[a],h=l+`[${'__'.repeat(a-1)}]`,
        v-s?R(z,h,[...p,v],k,v):R(z-1,h+'\n',[],p,0),
        ++b[a]
      ))
    :n=l
  )(h,'',[],[],0,n.map(n=>(b[n]=-~b[n],s+=n)),s/=h)&&n

// Test suite


out=x=>OUT.innerHTML=OUT.innerHTML+x+'\n'

;[ 
 [[1, 1, 2, 2], 2], [[1, 1, 1, 2, 2, 2, 2, 3], 2], [[1, 1, 2, 2, 3, 3, 3, 3], 3]
,[[1, 2, 3, 4, 5, 6, 7, 8, 9], 5], [[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 5]]
.forEach(([a,b])=>out(a+' '+b+'\n'+f(a,b)))
<pre id=OUT></pre>

Непорочний І пояснив

function f(n, h) {
  var b=[], s=0, result // in golfed version will re-use n for result variable
  n.forEach(function (n) {
    b[n] = -~b[n] // group equal input numbers in buckets
    s+=n          // calc sum of input numbers
  });
  // example of buckets: input 1,1,4,1,5,4 -> b[1]=3,b[4]=2,b[5]=1
  s /= h // total sum / height => sum expected for each brick layer

  // recursive scan function 
  function R(z, // layer count, from h downto 1
             l, // output so far
             p, // current layer partial sums array, mark intervals between bricks
             k, // prev layer parial sums, checked to avoid faulds
             t  // current partial sum 
             ) 
  {
    if (z > 0) 
    { // still building
      b.forEach( function (v,a) { // a:number from input list, v: repeat count 
        var w, m   // locals (in golfed version, reuse other variables avoid defining locals)
        w = t + a; // increased running total for current layer
        if (v != 0  // repeat count still > 0 
           && k.indexOf(w) < 0 // running total not found on list in prev layer (no fault)
           && w <= s) // current layer length not exceeded
        {
           --b[a]; // decrease repeat count, number used one more time
           m = l+"["+ '__'.repeat(a-1) + "]"; // new output with a brick added
           // l is not changed, it will be used again in this loop
           if (w == s) 
           {   // layer complete, go to next (if any)
               // recurse, new layer, add newline to output, p goes in k, and t start at 0 again
               R(z-1, m+'\n', [], p, 0); 
           }
           else
           {   // layer still to complete
               // recurse, same layer, m goes in l, add current sum to array p
               R(z, m, [...p,w], k, w);
           }
           ++b[a]; // restore value of repeat count for current loop
        }
      })
    }   
    else
    { // z == 0, all layers Ok, solution found, save in result and go on to next
      result = l;
    }
  }

  R(h,'',[],[],0);
  return result; // this is the last solution found
}

2

Python 2, метод сітки (290 символів)

x,h=input()
from itertools import *
w = sum(x)*2/h
for p in permutations(x):
 bricks = ''.join('[' + '_'*(2*n-2) + ']' for n in p)
 cols = map(''.join,zip(*zip(*[iter(bricks)]*w)))
 if all(c=='[' for c in cols[0]) and all(c==']' for c in cols[-1]) and not any(']]' in col or '[[' in col for col in cols[1:-1]):
  print('\n'.join(map(''.join,zip(*cols))))
  print()

Метод тут полягає в тому, щоб ви перемістити сітку і шукати [[або в ]]будь-якому місці в стовпцях. Ви також перевіряєте, що всі цеглини в лівій і правій частині стіни вирівнюються: мила річ - перевірити, що всі елементи струни однакові:'[[[[[['.strip('[')==''


міні-версія вище:

x,h=input()
from itertools import*
w=sum(x)*2/h
z=zip
j=''.join
for p in permutations(x):
 C=map(j,z(*z(*[iter(j('['+'_'*(2*n-2)+']'for n in p))]*w)))
 if C[0].strip('[')==''and C[-1].strip(']')==''and not any(']]'in c or '[['in c for c in C[1:-1]):
  print('\n'.join(map(j,z(*C))))
  break

Можливо, це можна зробити простіше мовою маніпулювання матрицею.

... або зловживання регулярними виразами, що дозволяє нам поєднувати стан "блоки вирівняти по кінцях" із умовою "без тріщин":

Скажімо, ширина стіни була w = 6. Розташування підрядків "[..... [", і "] .....]" повинно бути точно набором {0, w-1, w, 2w-1,2w, 3w-1 ,. ..}. Відсутність у цих точках означає цегла "переплітання рядків" так:

       v
[][__][_
___][__]
       ^

Існування НЕ в цих точках означає, що в стіні є нестійка «тріщина»:

     vv
[][__][]
[    ][]
     ^^

Тому ми зводимо задачу до встановлення еквівалентності, де множини у питаннях є індексами відповідності регулярного виразу.

# assume input is x and height is h

from itertools import *
import re
w=sum(x)*2/h

STACKED_BRACKET_RE = r'(?=\[.{%i}\[|\].{%i}\])'%(w-1,w-1)  # ]....] or [....[
STRING_CHUNK_RE = '.{%i}'%w  # chunk a string with a regex!
bracketGoal = set().union(*[(x*w,x*w+w-1) for x in range(h-1)])  # expected match locations

for p in permutations(x):
 string = ''.join('['+'_'*(2*n-2)+']'for n in p)
 bracketPositions = {m.start() for m in re.finditer(STACKED_BRACKET_RE,string)}
 print(string, bracketPositions, bracketGoal, STACKED_BRACKET_RE) #debug
 if bracketPositions==bracketGoal:
  break

print('\n'.join(re.findall(STRING_CHUNK_RE,string)))

Python, метод regexp (304 символів):

from itertools import*
import re
x,h=input()
w=sum(x)*2/h
for p in permutations(x):
 s=''.join('['+'_'*(2*n-2)+']'for n in p)
 if {m.start()for m in re.finditer(r'(?=\[.{%i}\[|\].{%i}\])'%(w-1,w-1),s)}==set().union(*[(x*w,x*w+w-1) for x in range(h-1)]):
  break

print('\n'.join(re.findall('.{%i}'%w,s)))

Цікава ідея роботи із настінним малюнком безпосередньо для перевірки несправностей. Вам потрібен рядок, щоб взяти вхід, наприклад x,h=input().
xnor

0

Матлаб (359)

function p(V),L=perms(V);x=sum(V);D=find(rem(x./(1:x),1)==0);for z= 2:numel(D-1)for y=1:numel(L),x=L(y,:);i=D(z);b=x;l=numel(x);for j=1:l,for k=j-1:-1:2,m=sum(x(1:k));if mod(m,i),if mod(m,i)<mod(sum(x(1:k-1)),i)||sum(x(1:j))-m==i,b=0;,end,end,end,end,if b,for j=1:l,fprintf('[%.*s]%c',(b(j)-2)+b(j),ones(9)*'_',(mod(sum(x(1:j)),i)<1)*10);end,return,end;end,end

Вхідні дані

вектор цілих чисел, наприклад: p ([1 1 2 2 3])

Вихідні дані

схема настінного прикладу:

[____]

[__][]

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