Construa uma parede de tijolos constante

39

Uma parede de tijolos é um retângulo feito de tijolos horizontais de 1 por n empilhados em linhas. Aqui está uma parede de altura 4 e largura 8, com tamanhos de tijolo mostrados à direita.

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

Essa parede é instável porque possui uma falha , um local onde duas fendas verticais entre os tijolos se alinham, mostradas abaixo com parênteses nos tijolos ao redor.

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

Mas, as rachaduras que cercam os tijolos tamanho 1 à direita não formam uma falha porque são separadas por uma linha.

Escreva um código que encontre e exiba uma parede firme construída com tijolos de tamanhos especificados. Menos bytes ganha.

Entrada

Uma lista não vazia de tamanhos de tijolos (números positivos) e uma altura de pelo menos 2. Essa lista pode ser classificada se você desejar. Como alternativa, você pode obter uma contagem de tijolos de cada tamanho.

Saída

Uma imagem de uma parede retangular estável da altura necessária que usa todos os tijolos fornecidos. Imprima ou retorne como uma sequência com novas linhas.

Desenhe um tijolo de tamanho n como 2n caracteres, sublinhados entre colchetes.

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

A entrada é garantida para ter pelo menos uma solução. Se houver vários, você ainda deve desenhar apenas uma parede.

Não há restrição de tempo; use a força bruta que quiser. Seu algoritmo deve, em teoria, trabalhar com entradas de qualquer tamanho.

Casos de teste:

Existem várias soluções, portanto, suas saídas podem ser diferentes.

>> [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
[][__][__]
[__][__][]
[][__][__]
[__][__][]
[][__][__]
xnor
fonte
por que você decidiu criar tijolos com 2n caracteres de largura em vez de n> 1 caracteres de largura?
Sparr
2
O @Sparr 1 por 2 blocos de caracteres parece mais ou menos quadrado. Tentei exigir n>1e não gostei de como isso restringia os casos de teste. Além disso, aparentemente há precedentes .
Xnor
Não quero dizer 2n com n> 1. Quero dizer n com n> 1.
Sparr

Respostas:

20

Perl, 166 170 194

Uma tarefa perfeita para um idioma criado por Larry Wall.

#!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

Força bruta, mas bastante rápida nos casos de teste (<1s). Uso:

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

Teste- me .

nutki
fonte
9
Ha, eu me pergunto se Larry Wall nunca pensei que as pessoas estariam usando a linguagem assim ... :)
crazyhatfish
12

CJam, 94 92 82 bytes

Esta é a versão de 92 bytes. Versão de 82 bytes a seguir.

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

Isso divide os tijolos de todas as formas possíveis e leva apenas o que é válido. Força bruta por enquanto, mas ainda executa o último caso de teste em cerca de 10 segundos no Java Interpreter na minha máquina.

Explicação :

O código é dividido em 5 partes:

1) Dada uma variedade de comprimentos L, como todos podemos particioná-lo em Hpartes.

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

Depois disso, temos todas as formas possíveis de dividir nossa matriz de entrada em camadas de tijolo H.

2) Obtenha todas as permutações da matriz de entrada e depois obtenha ainda mais todas as partições para todas as permutações

\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

Depois disso, temos todos os layouts possíveis dos tijolos de entrada em uma Hparede de tijolos de camadas.

3) Filtre apenas os layouts cujos comprimentos de tijolo sejam iguais

{::+)-!},
{      },              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.

Após o final desse filtro, todos os layouts restantes seriam retângulos perfeitos.

4) Retire o primeiro layout de tijolo que corresponda aos critérios de estabilidade

{{_,,\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

Após esta etapa, basta imprimir o layout

5) Imprima o layout

{{(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

Experimente online aqui


82 bytes

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

Isso é quase semelhante à versão de 92 bytes, exceto pelo fato de ter um toque de aleatoriedade. Se você leu a explicação para a versão de 92 bytes, na versão de 82 bytes, as partes 3, 4 e 5 são exatamente iguais, enquanto em vez de iterar todas as permutações das partes 1 e 2, essa versão simplesmente gera aleatoriamente um dos permutação de cada vez, testa usando as partes 3 e 4 e, em seguida, reinicia o processo se os testes das partes 3 e 4 falharem.

Isso imprime os resultados muito rapidamente para os três primeiros casos de teste. O caso de teste height = 5 ainda não deu uma saída no meu computador.

Explicação da diferença

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

A idéia para esta versão foi dada por randomra (Entendeu?)

Experimente este online

Optimizer
fonte
9

Python 2, 680 670 660 bytes

Não sei por que insisto em ter esses "golfinhos" super longos ... mas, enfim, aqui está.

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))

Isso requer a saída em ordem crescente classificada e é chamado via b(brick_sizes, height).

Casos de teste:

>>> 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
... 
[__][]
[][__]

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

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

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

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

A maneira como isso funciona é:

  1. Atribua os tijolos (maior-> menor) às camadas, tentando preencher cada camada antes de passar para a próxima.
  2. Sempre que as camadas adjacentes forem instáveis, tente trocar as camadas e trocar os tijolos até encontrar algo que funcione.
  3. Se nada funcionar, mova o tijolo mais longo para a frente da lista de tamanhos e recorra.
sirpercival
fonte
1
Você provavelmente pode soltar o continuede perto do fim. Também return(N,N)não precisará do parêntese.
PurkkaKoodari
boa ligação - isso continueera uma relíquia de uma versão anterior.
Sirpercival
1
Não é possível executá-lo, você tem um colchete estranho We Trecebe um argumento extra.
22615 Crazyhatfish #
gritos, obrigado! fixo.
Sirpercival
5

Haskell, 262 bytes

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

Exemplo de uso:

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

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

Como funciona: a função principal #pega uma lista l(lista de tijolos) e um número h(altura) e divide todas as permutações de lem hsublistas em todas as posições possíveis (via função %, por exemplo, 2%[1,2,3,4]-> [ [[1],[2,3]] , [[1,2],[3]] , [[1,2,3],[]] ]). Mantém aqueles em que dois elementos consecutivos têm a mesma soma (ou seja, o mesmo comprimento em tijolos) e as listas de subtotais não possuem elementos comuns (ou seja, fendas não se alinham, função v). Pegue a primeira lista que se encaixa e construa uma série de tijolos.

nimi
fonte
4

Python 2, 528 , 417 , 393 , 381

Solução de força bruta muito longa. Funciona, mas é isso, o universo pode terminar antes de obter o resultado do último caso de teste.

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 principal função:

>> a([1, 1, 2, 2], 2)
'[][  ]\n[  ][]'
crazyhatfish
fonte
Você pode salvar 4 bytes alterando a importação from itertools import*e removendo itertools.da permutationschamada. Além disso, os ifs no final podem ser alterados para if all(x==w[0] for x in w)and~-f(o):return... para salvar 13 bytes.
PurkkaKoodari
Além disso, nem fsempre retorna na primeira iteração? Isso parece estranho. É um bug ou uma enorme oportunidade de golfe.
PurkkaKoodari
Você tem vários espaços externos que podem ser removidos - antes ou depois de uma cotação / paren / colchete, ao redor de um operador, etc. Você também está designando t=0duas vezes r(); você pode transformar essa função em map(sum,[x[:i] for i in range(len(x))])uma linha (adequada para lambda-ing, se desejar). O uso de isdisjoint e sets in f()o reduziria significativamente (também f()retorna atualmente após apenas um teste, independentemente de ter encontrado um erro ou não). Pessoalmente, eu reescreveria f()como return not all(map(isdisjoint,map(set,map(r,w[:-1])),map(set,map(r,w[1:]))))ou algo semelhante.
Sirpercival
@ Pietu1998 Ah, sim, perdi um espaço. Obrigado pelas dicas pessoal, fiquei surpreso que você consiga perceber essas coisas.
22615 crazyhatfish
rindo muito ruim eu odeio esse tipo de códigos, onde "o universo pode acabar antes de começar o resultado", mas este é mais curto bytes cotest mais o que fazer xD
Abr001am
3

JavaScript (ES6) 222 232 265 279 319

Ainda para ser jogado golfe. Este encontra todas as soluções, produz apenas a última encontrada, e é bastante rápido.

Execute o snippet no Firefox para testar

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>

Ungolfed And Explained

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
}
edc65
fonte
2

Python 2, método de grade (290 caracteres)

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()

O método aqui é você transpor a grade e procurar um [[ou ]]em qualquer lugar nas colunas. Você também testa se todos os tijolos do lado esquerdo e direito da parede estão alinhados: o mais interessante aqui é testar se todos os elementos de uma string são iguais:'[[[[[['.strip('[')==''


mini versão acima:

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

Provavelmente isso poderia ser feito mais facilmente em uma linguagem de manipulação de matrizes.

... ou abuso de expressões regulares, o que nos permite combinar a condição "alinhar os blocos nas extremidades" com a condição "sem rachaduras":

Digamos que a largura da parede fosse w = 6. Os locais da substring "[..... [" e "] .....]" devem ser exatamente o conjunto {0, w-1, w, 2w-1,2w, 3w-1 ,. ..}. A inexistência nesses pontos significa que os tijolos são 'enrolados' da seguinte maneira:

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

A existência NÃO nesses pontos significa que há uma rachadura instável na parede:

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

Portanto, reduzimos o problema para definir equivalência, onde os conjuntos em perguntas são os índices de uma correspondência de expressão regular.

# 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, método regexp (304 caracteres):

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)))
ninjagecko
fonte
Idéia interessante ao trabalhar diretamente com a imagem da parede para verificar falhas. Você precisa de uma linha para receber a entrada, como x,h=input().
Xnor 17/05
0

Matlab (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

Entrada

um vetor de números inteiros, exemplo: p ([1 1 2 2 3])

Saída

o esquema do exemplo de parede:

[____]

[__][]

[][__]
Abr001am
fonte