Classifique minimamente uma lista em uma matriz

18

Dada uma lista não classificada de números inteiros estritamente positivos exclusivos, classifique-a minimamente em uma matriz 2D. A lista de entrada é a garantia de ser de comprimento compósito, o que significa que a matriz de saída não é necessariamente quadrado, mas é de tamanho n x mcom n,m > 1.

"Classificação mínima" aqui significa o seguinte:

  • Classifique a lista em ordem crescente.
  • Compactar a matriz de saída, tanto quanto possível - minimizar a soma das dimensões da matriz (por exemplo, por 20elementos de entrada como entrada, um 5x4ou 4x5matriz de saída é necessária, e não um 2x10).
  • Compacte os números classificados o mais alto possível à esquerda da matriz, começando com o primeiro elemento na lista classificada.
  • Isso pode ser considerado como classificar a lista e, em seguida, cortá-la ao longo das anti-diagonais da matriz, começando pelo canto superior esquerdo.

Exemplos:

Para 1..20saída de entrada é uma matriz 5x4 ou 4x5 da seguinte maneira:

 1  2  4  7 11
 3  5  8 12 15
 6  9 13 16 18
10 14 17 19 20

 1  2  4  7
 3  5  8 11
 6  9 12 15
10 13 16 18
14 17 19 20

Para [3, 5, 12, 9, 6, 11]saída de entrada é um 2x3 ou 3x2 da seguinte maneira

3  5  9
6 11 12

 3  5
 6  9
11 12

Para entrada [14, 20, 200, 33, 12, 1, 7, 99, 58], a saída é 3x3 da seguinte maneira

 1   7  14
12  20  58
33  99 200

Para entrada, 1..10a saída deve ser 2x5 ou 5x2 da seguinte maneira

1 2 4 6  8
3 5 7 9 10

1  2
3  4
5  6
7  8
9 10

Para [5, 9, 33, 65, 12, 7, 80, 42, 48, 30, 11, 57, 69, 92, 91]saída de entrada é um 5x3 ou 3x5 da seguinte maneira

 5  7 11 33 57
 9 12 42 65 80
30 48 69 91 92

 5  7 11
 9 12 33
30 42 57
48 65 80
69 91 92

Regras

  • Pode-se presumir que a entrada cabe no tipo inteiro nativo do seu idioma.
  • A entrada e saída podem ser fornecidas por qualquer método conveniente .
  • Um programa completo ou uma função são aceitáveis. Se uma função, você pode retornar a saída em vez de imprimi-la.
  • As brechas padrão são proibidas.
  • Isso é portanto todas as regras usuais de golfe se aplicam e o código mais curto (em bytes) vence.
AdmBorkBork
fonte
1
Oh, uau, uma palavra que eu não vi desde Álgebra Linear; facilmente esquecido. Me desculpe.
Magic Octopus Urn
@LuisMendo Adicionado um 15caso de teste de elemento.
AdmBorkBork 16/02

Respostas:

10

Gelatina , 24 22 20 bytes

pS€ỤỤs
LÆDżṚ$SÞḢç/ịṢ

Experimente online!

Economizou 2 bytes graças a @ Jonathan Allan .

Explicação

pS€ỤỤs  Helper link. Input: integer a (LHS), integer b (RHS)
p       Cartesian product between [1, 2, ..., a] and [1, 2, ..., b]
 S€     Sum each pair
   Ụ    Grade up
    Ụ   Grade up again (Obtains the rank)
     s  Split into slices of length b

LÆDżṚ$SÞḢç/ịṢ  Main link. Input: list A
L              Length
 ÆD            Divisors
     $         Monadic pair
    Ṛ            Reverse
   ż             Interleave
                 Now contains all pairs [a, b] where a*b = len(A)
      SÞ       Sort by sum
        Ḣ      Head (Select the pair with smallest sum)
         ç/    Call helper link
            Ṣ  Sort A
           ị   Index into sorted(A)
milhas
fonte
L%J¬TżṚ$-> LÆDżṚ$deve salvar dois eu acho
Jonathan Allan
O primeiro link pode se tornar pSÞỤs.
24518 Dennis
4

Python 2 , 160 158 153 151 bytes

-2 bytes graças a Erik, o Outgolfer
-2 bytes graças a Mr. Xcoder

s=sorted(input())
l=len(s)
x=int(l**.5)
while l%x:x+=1
n=1
o=eval(`l/x*[[]]`)
while s:
 for i in range(l/x)[max(0,n-x):n]:o[i]+=s.pop(0),
 n+=1
print o

Experimente online! ou Experimente todos os casos de teste

Cajado
fonte
Eu acredito que você pode usar max(0,n-x)para -2 bytes.
Mr. Xcoder
4

R 110 95 bytes

function(x){n=sum(x|1)
X=matrix(x,max(which(!n%%1:n^.5)))
X[order(col(X)+row(X))]=sort(x)
t(X)}

Experimente online!

Como funciona

f <- function(x) {
  n <- sum(x|1)                           # length
  p <- max(which(!n%%1:n^.5))             # height of matrix
  X <- matrix(x, p)                       # initialize matrix
  X[order(col(X) + row(X))] <- sort(x)    # filling the matrix using position distance to the top left corner
  t(X)                                    # probably required by OP
}

Giuseppe salvou 15 (!) Bytes pelos truques a seguir

  • substituindo length(x)por sum(x|1)(-1 byte)
  • floor()não é necessário, pois :arredonda para baixo de qualquer maneira (-7)
  • ^.5é menor que sqrt()(-3)
  • usando em col(X) + row(X)vez de outer(bom!)
  • não conseguia se livrar do t(X)embora - decepcionante;)

Solução original

function(x){
n=length(x)
p=max(which(!n%%1:floor(sqrt(n))))
X=outer(1:p,1:(n/p),`+`)
X[order(X)]=sort(x)
t(X)}

Seria mais chique outerser substituído por row(X)+col(X), mas seria necessário inicializar a matriz de saída Xprimeiro.

Experimente online!

Michael M
fonte
2
Muito agradável! Você pode obter 95 bytes
Giuseppe
1
Pode ser capaz de usar algo da minha solução para um desafio relacionado para ajudar aqui também.
27418 Giuseppe
De fato, está intimamente relacionado. Abordagem muito agradável!
22618 Michael M
3

JavaScript (ES6), 172 bytes

l=>(n=l.sort((a,b)=>b-a).length,w=l.findIndex((_,i)=>!(i*i<n|n%i)),a=l=>[...Array(l)],r=a(n/w).map(_=>a(w)),a(w+n/w).map((_,x)=>r.map((s,y)=>x-y in s&&(s[x-y]=l.pop()))),r)

Explicação

l=>(                                // Take a list l as input
 l.sort((a,b)=>b-a),                // Sort it
 n=l.length,                        // Get the length n
 w=l.findIndex((_,i)=>!(i*i<n|n%i)),// Find the first integer w where w >= √n and n % w = 0
 a=l=>[...Array(l)],                // Helper function a
 r=a(n/w).map(_=>a(w)),             // Create the grid r of size w, n/w
 a(w+n/w).map((_,x)=>               // For every x from 0 to w + n/w:
  r.map((s,y)=>                     //  For every row s in r:
   x-y in s&&(                      //   If the index x-y is in s:
    s[x-y]=l.pop()))),              //    Set s[x-y] to the next element of l
 r)                                 // Return r

Casos de teste

Herman L
fonte
3

Perl 5 , 132 bytes

sub d{$,=0|sqrt(@_=sort{$a-$b}@_);--$,while@_%$,;map{$r++,$c--for@_/$,..$c;$a[$r++][$c--]=$_;$c=++$i,$r=0if$r<0||$c<0||$r>=$,}@_;@a}

Experimente online!

A sub-rotina retorna uma matriz 2-D. O link TIO inclui código de rodapé para exibir o resultado do teste.

Xcali
fonte
3

Oitava , 151 bytes

function f(v)n=floor(sqrt(l=nnz(v)));while i=mod(l,n);++n;end;A=nan(m=l/n,n);for k=[1:m 2*m:m:l];do A(k)=sort(v)(++i);until~mod(k+=m-1,m)|k>l;end;A'end

Usando três tipos diferentes de construções de loop.

Experimente online!

Desenrolado:

function f(v)
    n = floor(sqrt(l=nnz(v)));

    while i = mod(l,n);
        ++n;
    end;

    A = nan(m=l/n, n);

    for k = [1:m 2*m:m:l];
        do
            A(k) = sort(v)(++i);
        until ~mod(k+=m-1, m) | k>l;
    end;

    A'
end
Steadybox
fonte
Boa resposta! Por que o 'in é nnz(v') necessário?
Luis Mendo
1
@LuisMendo Thanks! Acontece que 'não é necessário se eu envolver a expressão de intervalo, por exemplo 1:20, entre colchetes ( [1:20]) no local da chamada (para torná-lo um vetor real). Aparentemente, no Octave, o operador de dois pontos não cria um vetor , mas uma constante de intervalo que ocupa muito menos espaço na memória. Por alguma razão, nnz()não funciona com esse tipo, mas a transposição da constante de intervalo gera um vetor, portanto, funciona com o apóstrofo. Chamar a função com um vetor real remove a necessidade de '.
Steadybox
1
Obrigada pelo esclarecimento. Eu não sabia que uma expressão de alcance tinha esse tratamento especial no Octave. De qualquer forma, o fato de não criar um vetor para eficiência da memória deve ser transparente para o programador. Ou seja, o fato de nnz(1:20)não funcionar provavelmente é um bug ( max(1:20), sum(1:20)etc são válidos).
Luis Mendo
1
Deveríamos denunciá-lo . Pode afetar outras funções além de nnz. Você quer fazer você mesmo, ou devo?
Luis Mendo
1
Relatado . Também afetou o MATL; agora resolvido . Obrigado por perceber isso!
Luis Mendo
0

Casca , 15 bytes

ḟȯΛ≤Σ∂MCP¹→←½ḊL

Isso funciona com força bruta, então casos de teste mais longos podem atingir o tempo limite. Experimente online!

Explicação

ḟȯΛ≤Σ∂MCP¹→←½ḊL  Implicit input, a list of integers x.
              L  Length of x (call it n).
             Ḋ   List of divisors.
            ½    Split at the middle.
          →←     Take last element of first part.
                 This is a divisor d that minimizes d + n/d.
        P¹       List of permutations of x.
      MC         Cut each into slices of length d.
ḟ                Find the first of these matrices that satisfies this:
     ∂            Take anti-diagonals,
    Σ             flatten them,
 ȯΛ≤              check that the result is sorted (each adjacent pair is non-decreasing).
Zgarb
fonte
0

C (gcc) , 269 bytes

j,w,h,x,y;f(A,l)int*A;{int B[l];for(w=l;w-->1;)for(j=0;j<w;)if(A[j++]>A[j]){h=A[~-j];A[~-j]=A[j];A[j]=h;}for(w=h=j=2;w*h-l;j++)l%j||(w=h,h=j),h*h-l||(w=j);for(x=0;x<w*h;x++)for(y=0;y<=x;y++)x-y<w&y<h&&(B[x-y+y*w]=*A++);for(j=0;j<l;j++)j%w||puts(""),printf("%d ",B[j]);}

Experimente online!

Jonathan Frech
fonte
0

JavaScript (ES6), 233 bytes

f=s=>{l=s.length;i=Math.sqrt(l)|0;for(;l%++i;);p=(x)=>(x/i|0+x%i)*l+x%i;m=[...Array(l).keys()].sort((x,y)=>p(x)-p(y));return s.sort((a,b)=>a-b).map((x,i)=>m.indexOf(i)).reduce((a,b,d,g)=>!(d%i)?a.concat([g.slice(d,d+i)]):a,[])}

Explicação

f=s=>{                         // Take array `s` of numbers as input
  l=s.length                   // short-hand for length
  i=Math.sqrt(l)|0             // = Math.floor(Math.sqrt(l))
  for(;l%++i;);                // i = width           
  j=l/i                        // j = height

  p=(x)=>(x/i|0+x%i)*l+x%i     // helper to calculate (sort-of) ~manhattan
                                 // distance (horizontal distance weighted
                                 // slightly stronger), from top-left corner
                                 // to the number x, if numbers 0,...,l are
                                 // arranged left-to-right, top-to-bottom
                                 // in an l=i*j grid

  m=[...Array(l).keys()]         // range array
  .sort((x,y)=>p(x)-p(y)),       // manhatten-sorted, sort-of...

  return s.sort((a,b)=>a-b)      // sort input array by numbers,
    .map((x,i,w)=>w[m.indexOf(i)])    // then apply inverse permutation of the
                                 // range-grid manhatten-sort mapping.
    .reduce(                     // slice result into rows
      (a,b,d,g)=>!(d%i)?a.concat([g.slice(d,d+i)]):a
      ,[]
     )
}
trollkotze
fonte
0

Java 10, 199 188 186 bytes

a->{int j=a.length,m=0,n,i=0,k=0;for(n=m+=Math.sqrt(j);m*n<j;n=j/++m);var R=new int[m][n];for(java.util.Arrays.sort(a);i<m+n;i++)for(j=0;j<=i;j++)if(i-j<n&j<m)R[j][i-j]=a[k++];return R;}

Experimente online.

Com base na minha resposta aqui .

Explicação:

a->{                        // Method with int-array parameter and int-matrix return-type
  int j=a.length,           //  Length of the input-array
      m=0,n,                //  Amount of rows and columns
      i=0,k=0;              //  Index integers
   for(n=m+=Math.sqrt(j);   //  Set both `m` and `n` to floor(√ `j`)
       m*n<j;               //  Loop as long as `m` multiplied by `n` is not `j`
       n=j/++m);            //   Increase `m` by 1 first with `++m`
                            //   and then set `n` to `j` integer-divided by this new `m`
   var R=new int[m][n];     //  Result-matrix of size `m` by `n`
   for(java.util.Arrays.sort(a);
                            //  Sort the input-array
       i<m+n;)              //  Loop as long as `i` is smaller than `m+n`
     for(j=0;j<=i;j++)      //   Inner loop `j` in range [0,`i`]
       if(i-j<n&j<m)        //    If `i-j` is smaller than `n`, and `j` smaller than `m`
                            //    (So basically check if they are still within bounds)
         R[j][i-j]=a[k++];  //     Add the number of the input array at index `k`,
                            //     to the matrix in the current cell at `[j,i-j]`
  return R;}                //  Return the result-matrix
Kevin Cruijssen
fonte