Costruisci un muro di mattoni stabile


39

Un muro di mattoni è un rettangolo fatto di mattoni orizzontali 1-by-n impilati in file. Ecco un muro di altezza 4 e larghezza 8, con le dimensioni dei mattoni mostrate a destra.

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

Questo muro è instabile perché ha un difetto , un luogo in cui due fessure verticali tra i mattoni si allineano, mostrato sotto con le parentesi nei mattoni circostanti.

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

Ma le crepe che confinano con i mattoni di taglia 1 a destra non formano un difetto perché sono separate da una fila.

Scrivi il codice che trova e visualizza un muro stabile costruito con mattoni di dimensioni specificate. Vince il minor numero di byte.

Ingresso

Un elenco non vuoto di dimensioni del mattone (numeri positivi) e un'altezza che sia almeno 2. Se lo desideri, questo elenco può essere ordinato. In alternativa puoi prendere in considerazione un numero di mattoni di ogni dimensione.

Produzione

Un'immagine di una parete rettangolare fissa dell'altezza richiesta che utilizza tutti i mattoni forniti. Stampalo o restituiscilo come una stringa con newline.

Disegna un mattone di dimensione n come 2n caratteri, i trattini bassi racchiusi tra parentesi.

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

È garantito che l'input abbia almeno una soluzione. Se ce ne sono molti, dovresti comunque disegnare solo un muro.

Non ci sono limiti di tempo; usa tutta la forza bruta che vuoi. Il tuo algoritmo dovrebbe in teoria funzionare su input di qualsiasi dimensione.

Casi test:

Esistono più soluzioni, quindi i tuoi risultati potrebbero essere diversi.

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

perché hai deciso di creare mattoni di 2n di larghezza anziché di n> 1 di larghezza?
Sparr,

2
I blocchi di caratteri @Sparr 1 per 2 sembrano approssimativamente quadrati. Avevo provato a richiedere n>1e non mi piaceva come limitasse i casi di test. Inoltre, a quanto pare c'è un precedente .
xnor

Non intendo 2n con n> 1. Intendo n con n> 1.
Sparr,

Risposte:


20

Perl, 166 170 194

Un compito perfetto per un linguaggio creato da 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

Forza bruta, ma abbastanza veloce sui casi di test (<1s). Uso:

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

Metti alla prova me .


9
Ah, mi chiedo se Larry Wall abbia mai pensato che le persone avrebbero usato la lingua in quel modo ... :)
crazyhatfish

12

CJam, 94 92 82 byte

Questa è la versione da 92 byte. Segue la versione da 82 byte.

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

Questo divide i mattoni in ogni modo possibile e prende solo quello che è valido. Forza abbastanza bruta per ora, ma esegue ancora l'ultimo caso di test in circa 10 secondi sull'interprete Java sulla mia macchina.

Spiegazione :

Il codice è diviso in 5 parti:

1) Dato un array di lunghezza L, come tutti possiamo dividerlo in Hparti.

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

Dopodiché, abbiamo tutti i modi possibili per suddividere il nostro array di input in strati di mattoni H.

2) Ottieni tutte le permutazioni dell'array di input e quindi ottieni tutte le partizioni per tutte le permutazioni

\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

Successivamente, abbiamo tutti i possibili layout dei mattoni di input in un Hmuro di mattoni a strati.

3) Filtrare solo quei layout le cui lunghezze dei mattoni sono uguali

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

Dopo la fine di questo filtro, tutti i layout rimanenti sarebbero rettangoli perfetti.

4) Estrarre il primo layout in mattoni che corrisponde ai criteri di stabilità

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

Dopo questo passaggio, dobbiamo semplicemente stampare il layout

5) Stampa il 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

Provalo online qui


82 byte

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

Questo è quasi simile alla versione a 92 byte, tranne per il fatto che ha un tocco di casualità. Se hai letto la spiegazione per la versione da 92 byte, quindi nella versione da 82 byte, le parti 3, 4 e 5 sono esattamente le stesse, mentre invece di iterare su tutte le permutazioni delle parti 1 e 2, questa versione genera semplicemente una delle casuali permutazione alla volta, lo testa usando le parti 3 e 4, quindi riavvia il processo se i test della parte 3 e 4 falliscono.

Questo stampa i risultati molto rapidamente per i primi 3 casi di test. Il case test height = 5 deve ancora fornire un output sul mio computer.

Spiegazione della differenza

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

L'idea per questa versione è stata data da randomra (capito?)

Prova questo online


9

Python 2, 680 670 660 byte

Non so perché insisto per avere questi "golf" super lunghi ... ma comunque, eccoti.

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

Ciò richiede l'output in ordine crescente ordinato e viene chiamato via b(brick_sizes, height).

Casi test:

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

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

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

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

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

Il modo in cui funziona è:

  1. Assegna i mattoni (il più lungo-> il più corto) ai livelli, cercando di riempire ogni strato prima di passare al successivo.
  2. Ogni volta che i livelli adiacenti sono instabili, prova a scambiare i livelli e a spostare i mattoni fino a trovare qualcosa che funzioni.
  3. Se non funziona nulla, sposta il mattone più lungo in primo piano nell'elenco delle taglie e ricomincia.

1
Probabilmente puoi far cadere il continueda vicino alla fine. Inoltre return(N,N)non sarà necessaria la parentesi.
PurkkaKoodari,

buona chiamata - quella continueera una reliquia di una versione precedente.
sirpercival

1
Non riesci a farlo funzionare, hai una parentesi estranea inserita We Tviene superato un argomento in più.
crazyhatfish

spiacenti, grazie! fisso.
sirpercival

5

Haskell, 262 byte

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

Esempio di utilizzo:

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

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

Come funziona: la funzione principale #prende un elenco l(elenco di mattoni) e un numero h(altezza) e divide tutte le permutazioni lin helenchi secondari in tutte le posizioni possibili (tramite la funzione %, ad es. 2%[1,2,3,4]-> [ [[1],[2,3]] , [[1,2],[3]] , [[1,2,3],[]] ]). Mantiene quelli in cui due elementi consecutivi hanno la stessa somma (cioè la stessa lunghezza in mattoni) e gli elenchi dei subtotali non hanno elementi comuni (cioè le crepe non si allineano, funzionano v). Prendi il primo elenco adatto e costruisci una serie di mattoni.


4

Python 2, 528 , 417 , 393 , 381

Soluzione molto lunga, bruteforce. Funziona ma questo è tutto, l'universo potrebbe finire prima di ottenere il risultato per l'ultimo caso di test.

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 è la funzione principale:

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

È possibile salvare 4 byte modificando l'importazione from itertools import*e rimuovendola itertools.dalla permutationschiamata. Inoltre, la ifs alla fine può essere cambiata in if all(x==w[0] for x in w)and~-f(o):return... per salvare 13 byte.
PurkkaKoodari,

Inoltre, non fritorna sempre alla prima iterazione? Sembra strano. È un bug o un'enorme opportunità di golf.
PurkkaKoodari,

Hai una tonnellata di spazi estranei che possono essere rimossi - prima o dopo un preventivo / parentesi / parentesi, che circonda un operatore, ecc. Assegna anche t=0due volte r(); puoi fare quella funzione map(sum,[x[:i] for i in range(len(x))])come una fodera (adatta se vuoi). L'uso di isdisjoint e set in f()lo ridurrebbe in modo significativo (anche al f()momento restituisce dopo un solo test, indipendentemente dal fatto che sia stato trovato un errore). Personalmente riscriverei f()come return not all(map(isdisjoint,map(set,map(r,w[:-1])),map(set,map(r,w[1:]))))o qualcosa di simile.
sirpercival

@ Pietu1998 Oh sì, mi mancava uno spazio. Grazie per i suggerimenti ragazzi, mi sono meravigliato che possiate individuare queste cose.
crazyhatfish

ridendo troppo, odio quel tipo di codici in cui "l'universo potrebbe finire prima di ottenere il risultato", ma questo è il byte più corto più piccolo che altro da fare xD
Abr001am

3

JavaScript (ES6) 222 232 265 279 319

Ancora da giocare a golf. Questo trova tutte le soluzioni, produce solo l'ultimo trovato ed è abbastanza veloce.

Esegui lo snippet in Firefox per testarlo

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 e spiegato

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, metodo grid (290 caratteri)

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

Il metodo qui è trasporre la griglia e cercare una [[o ]]ovunque nelle colonne. Testerai anche che tutti i mattoni sui lati sinistro e destro del muro si allineano: la cosa carina qui è testare che tutti gli elementi di una stringa sono uguali:'[[[[[['.strip('[')==''


versione mini sopra:

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

Ciò potrebbe probabilmente essere fatto più facilmente in un linguaggio di manipolazione della matrice.

... o abuso di regex, che ci permette di combinare la condizione "blocchi allineati alle estremità" con la condizione "nessuna crepa":

Dire che la larghezza del muro era w = 6. Le posizioni della sottostringa "[..... [" e "] .....]" devono essere esattamente l'insieme {0, w-1, w, 2w-1,2w, 3w-1 ,. ..}. La non esistenza in quei punti significa che il 'linewrap' dei mattoni è così:

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

L'esistenza NON in questi punti significa che c'è una "crepa" instabile nel muro:

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

Pertanto riduciamo il problema per impostare l'equivalenza, in cui gli insiemi nelle domande sono gli indici di una corrispondenza di espressione regolare.

# 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, metodo regexp (304 caratteri):

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

Idea interessante lavorare direttamente con l'immagine della parete per verificare la presenza di guasti. Hai bisogno di una linea per prendere l'input, come x,h=input().
xnor

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

Ingresso

un vettore di numeri interi, esempio: p ([1 1 2 2 3])

Produzione

lo schema dell'esempio del muro:

[____]

[__][]

[][__]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.