Determinante 2x2 recursivo

17

O determinante de uma matriz 2 por 2

a b
c d

é dado por ad - bc.

Dada uma matriz de dígitos com dimensões 2 n por 2 n , n ≥ 1, produza o resultado obtido computando recursivamente o determinante de cada sub-bloco 2 por 2 até chegarmos a um único número.

Por exemplo, dada a entrada

3 1 4 1
5 9 2 6
5 3 5 8
9 7 9 3

Após uma etapa, obtemos:

(3*9 - 1*5)    (4*6 - 1*2)    =    22  22
(5*7 - 3*9)    (5*3 - 8*9)         8  -57

E iterando mais uma vez, obtemos:

(22*-57 - 22*8) = -1430

Portanto, a saída deve ser -1430.

Regras

  • Os elementos da matriz sempre serão números inteiros de um dígito, ou seja, 0 a 9.
  • Você pode receber entradas em qualquer formato conveniente de lista ou string, desde que não seja feito nenhum pré-processamento de dados. Como a matriz é sempre quadrada, você pode receber a entrada como uma única lista 1D em vez de uma lista 2D, se desejar.
  • A entrada pode ser via entrada de função, STDIN, argumento de linha de comando ou alternativa mais próxima.
  • A saída deve ser um único inteiro para funcionar como saída, STDOUT ou a alternativa mais próxima. Você não pode emitir o único inteiro em uma lista ou matriz.
  • Você pode usar métodos internos de determinação de determinantes e de matriz se o seu idioma os suportar.
  • Seu algoritmo deve funcionar em teoria para qualquer entrada válida.
  • Aplicam-se as regras de padrão .

Casos de teste

Os seguintes casos de teste são fornecidos como listas no estilo Python:

[[1,0],[0,1]] -> 1
[[1,9],[8,4]] -> -68
[[0,1,2,3],[4,5,6,7],[8,9,0,1],[2,3,4,5]] -> 40
[[3,1,4,1],[5,9,2,6],[5,3,5,8],[9,7,9,3]] -> -1430
[[9,0,0,9],[0,9,9,0],[9,0,9,0],[0,9,0,9]] -> 13122
[[1,0,0,0,0,0,0,0],[2,1,0,0,0,0,0,0],[3,2,1,0,0,0,0,0],[4,3,2,1,0,0,0,0],[5,4,3,2,1,0,0,0],[6,5,4,3,2,1,0,0],[7,6,5,4,3,2,1,0],[8,7,6,5,4,3,2,1]] -> 1
[[7,1,0,5,8,0,1,5],[9,9,6,6,1,2,4,8],[4,8,7,3,8,7,4,7],[4,6,1,9,7,0,1,7],[7,6,7,1,9,4,1,6],[8,0,0,8,5,5,9,9],[4,6,4,8,9,4,8,6],[9,0,8,7,6,2,1,5]] -> 2937504
[[1,2,3,4,5,6,7,8],[2,3,4,5,6,7,8,1],[3,4,5,6,7,8,1,2],[4,5,6,7,8,1,2,3],[5,6,7,8,1,2,3,4],[6,7,8,1,2,3,4,5],[7,8,1,2,3,4,5,6],[8,1,2,3,4,5,6,7]] -> -10549504
[[1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,0,0,1,0,1,1,1,1,1,1,0],[1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0],[0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1],[1,0,1,0,1,1,1,0,0,1,1,1,1,0,1,0],[0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0],[1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,1,1,1,1,1,1,1,1,0,0,1,0,1,0,1],[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,0],[1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,0,1,0,1,0,1,1,1,1,1,0,1],[1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1]] -> -8

(Obrigado a @ MartinBüttner pela ajuda com este desafio)

Sp3000
fonte
3
Curiosidade: fiz algumas experiências sobre isso e há um número surpreendentemente grande de matrizes binárias com determinante recursivo diferente de zero. Para os tamanhos 2x2, 4x4, 8x8, 16x16, obtivemos 6, 16488, 2229617029168687104, 3349795881591711813037585032680117995553655026185547430764970842694019448832 matrizes com determinante não zero, que corresponde a 37,5%, 12%, respectivamente, respectivamente.
Martin Ender
@ MartinBüttner: recebo 6, 22560, 10160459763342013440, ... que corresponde a A055165 .
Charles
@Charles estranho, eu vou verificar o meu código
Martin Ender
@ MartinBüttner: Possivelmente estamos apenas computando duas coisas diferentes?
Charles
@ Charles Considere a matriz [1,0,1,0;1,1,1,1;1,1,1,1;0,0,0,1]. O determinante completo é zero, pois possui duas linhas idênticas. Esta é, portanto, uma matriz 4 × 4 singular (ou seja, não invertível), portanto não é contada por A055165. No entanto, o determinante "recursivo" discutido aqui é 1*1-1*0==1. Na direção oposta, a matriz [0,0,0,1;1,0,0,0;0,1,0,0;0,0,1,0]possui determinante "recursivo" 0*0-0*0==0. No entanto, seu determinante completo deve ser diferente de zero, porque suas linhas são apenas as linhas da matriz de identidade em outra ordem; e é contado por A055165.
Jeppe Stig Nielsen

Respostas:

8

J, 21 25 bytes

0{0{(_2(_2-/ .*\|:)\])^:_

Uso:

   ]input=.(3,1,4,1),(5,9,2,6),(5,3,5,8),:(9,7,9,3)
3 1 4 1
5 9 2 6
5 3 5 8
9 7 9 3
   (0{0{(_2(_2-/ .*\|:)\])^:_) input
_1430

Em cada etapa, cortamos a matriz para 2 por 2 e calculamos cada determinante, resultando na matriz de entrada da próxima etapa. Repetimos esse processo até que o resultado não mude (o elemento final é o próprio determinante). Convertemos o resultado final em um escalar com 0{0{.

Experimente online aqui.

randomra
fonte
Tentei usar a função de lado a lado do Cut para fazer isso, mas não foi capaz de jogar tanto quanto a sua versão. 29 bytes: (2 2$2)&(-/ .*;._3^:(2^.#@])) Experimente online!
Jonah #
4

Mathematica, 52 40 bytes

Obrigado a Martin Büttner por salvar 12 bytes.

Tr[#//.l:{_,__}:>BlockMap[Det,l,{2,2}]]&

Explicação

BlockMap[f,expr,n]dividido exprem sublistas de tamanho ne mapa fem todas as sublistas. BlockMap[Det,#,{2,2}]&divida a matriz de entrada em 2 * 2 blocos e calcule seus determinantes.


Caso de teste

%[{{3,1,4,1},{5,9,2,6},{5,3,5,8},{9,7,9,3}}]
(* -1430 *)
njpipeorgan
fonte
11
Eu escrevi uma implementação de referência no Mathematica enquanto discutia a idéia do desafio com o Sp3000 e seus 40 bytes. É bem parecido com o seu, então eu darei a você algum tempo para encontrá-lo, se quiser. :)
Martin Ender
@ MartinBüttner eu falhei. :(
njpipeorgan
11
Você pode evitar o [[1,1]]com Tre o Nestcom //.:Tr[#//.l:{_,__}:>BlockMap[Det,l,{2,2}]]&
Martin Ender
@ MartinBüttner Na verdade, eu vim com //. ideia ao ler a resposta em J, mas não conseguiu encontrar uma boa maneira de combinar a matriz. : P
njpipeorgan
fique à vontade para usar minha solução para actualizar a sua resposta
Martin Ender
3

Geléia, 20 17 bytes

s€2s2U×¥/€ḅ-µL¡SS

Experimente online! ou verifique todos os casos de teste de uma só vez .

Como funciona

s€2s2U×¥/€ḅ-µL¡SS  Main link. Input: M (matrix)

s€2                Split each row of M into pairs.
   s2              Split the result into pairs of rows.
        /€         Reduce each pair...
       ¥             by applying the following, dyadic chain:
     U                 Reverse each pair of the left argument (1st row).
      ×                Multiply element-wise with the right argument (2nd row).
          ḅ-       Convert each resulting pair from base -1 to integer.
                   This maps [a, b] -> b - a.
            µ      Turn the previous links into a monadic chain. Begin a new one.
             L     Yield the length of the input.
              ¡    Execute the previous chain L times.
                   log2(L) times would do, but who's counting?
               SS  Sum twice to turn the resulting 1x1 matrix into a scalar.
Dennis
fonte
2

Haskell , 93 86 bytes

EDIT: Obrigado a @Laikoni por reduzir este total de 7 bytes!

f[[a,b],[c,d]]=a*d-b*c
f m|let l=[take,drop]<*>[div(length m)2]=f[f.($b<$>m)<$>l|b<-l]

Eu não sabia que você poderia colocar uma declaração let antes do = e nunca me acostumei com esses operadores de mônada. Mais uma vez obrigado @Laikoni

Versão antiga:

f[[a,b],[c,d]]=a*d-b*c
f m=f[[f$a$map b m|a<-l]|b<-l]where h=length m`div`2;l=[take h,drop h]

Experimente online!

Essa é uma função que se repete de duas maneiras diferentes. Primeiro, a correspondência de padrões captura o caso base: uma matriz 2x2 e faz o cálculo. Eu uso isso para fazer o cálculo no caso recursivo, chamando a função com uma matriz 2x2 que eu gero que possui as soluções recursivas. Essa matriz é gerada iterando duas vezes em uma matriz de funções que cada uma divide uma lista pela metade. Aplico-o a linhas com uma chamada simples e aplico-o a colunas usando map.

user1472751
fonte
Em vez de where h=length m`div`2;l=[take h,drop h], você pode usar f m|let l=[take,drop]<*>[length m`div`2]=. map b mpode ser b<$>me [f$a$b<$>m|a<-l]pode ser reduzido ainda mais f.($b<$>m)<$>l. Ao todo 86 bytes: [ tio.run/... Experimente online!]
Laikoni
1

Python, 166 bytes

def f(m):l=len(m)/2;g=lambda x,y:[(s[:l],s[l:])[x]for s in(m[:l],m[l:])[y]];return f(g(0,0))*f(g(1,1))-f(g(0,1))*f(g(1,0)) if l>1 else m[0][0]*m[1][1]-m[1][0]*m[0][1]

Isso passa em todos os casos de teste fornecidos. m deve ser uma matriz 2D (como nos casos de teste), g seleciona a sub-matriz.

basile-henry
fonte
1

Pyth, 26

M-F*VG_HhhumgMCcR2dcG2llQQ

Suíte de teste

Isso tem duas partes: M-F*VG_Hredefine a função gpara calcular o determinante de uma matriz dois por dois. Isso economiza bytes, embora o usemos apenas uma vez porque descompacta as duas linhas.

A outra parte é uma grande declaração de redução que chamamos de log_2( len( input() ) )tempos. Infelizmente, executar uma etapa da redução em uma matriz 1 por 1 faz com que o resultado seja agrupado em uma lista, para que não tenhamos um ponto fixo. A redução é basicamente dividir a matriz para obter matrizes 2 por 2 e depois aplicar g.

FryAmTheEggman
fonte
1

MATL , 26 30 bytes

`tnX^teHHhZC2Ih2#Y)pwp-tnq

Entrada é uma matriz 2D com linhas separadas por ;, ou seja,

[3 1 4 1; 5 9 2 6; 5 3 5 8; 9 7 9 3]

Experimente online!

`             % do...while loop
  tnX^te      %   reshape into square matrix. Implicitly asks for input the first time
  HHhZC       %   transform each 2x2 block into a column
  2Ih2#Y)     %   push matrix with rows 2,3, and also matrix with remaining rows (1,4)
  pwp-        %   multiplications and subtraction to compute the 2x2 determinants
  tnq         %   condition of do...while loop: is number of elements greater than 1?
              % implicitly end loop
              % implicitly display
Luis Mendo
fonte
1

Perl 5 , 120 + 1 ( -a) = 121 bytes

while($#F){@r=();for$i(@o=0..($l=sqrt@F)/2-1){push@r,$F[$k=$i*$l*2+2*$_]*$F[$k+$l+1]-$F[$k+$l]*$F[$k+1]for@o}@F=@r}say@F

Experimente online!

Toma a entrada como uma lista de números separados por espaço.

Xcali
fonte
0

ES6, 91 bytes

(a,x=0,y=0,w=a.length)=>(w>>=1)?f(a,x,y,w)*f(a,x+w,y+w,w)-f(a,x,y+w,w)*f(a,x+w,y,w):a[x][y]

Solução recursiva direta.

Neil
fonte
0

R , 111 bytes

f=function(m)"if"((n=nrow(m))-2,f(matrix(c(f(m[x<-1:(n/2),x]),f(m[y<-x+n/2,x]),f(m[x,y]),f(m[y,y])),2)),det(m))

Experimente online!

Recebe a entrada como uma matriz R (que é convertida pela função no cabeçalho).

Giuseppe
fonte
0

Groovy, 221 189 bytes (Neste ponto, poderia ter usado Java)

f={x->b=x.size();c=b/2-1;a=(0..c).collect{i->(0..c).collect{j->z=x.toList().subList(i*2,i*2+2).collect{it.toList().subList(j*2,j*2+2)};z[0][0]*z[1][1]-z[0][1]*z[1][0];}};a.size()==1?a:f(a)}

Versão antiga ruim, que também pode ser Java (221 bytes):

f={x->b=x.size();a=new int[b/2][b/2];for(i=0;i<b-1;i+=2){for(j=0;j<b-1;j+=2){z=x.toList().subList(i,i+2).collect{it.toList().subList(j,j+2)};a[(int)(i/2)][(int)(j/2)]=z[0][0]*z[1][1]-z[0][1]*z[1][0];}};a.size()==1?a:f(a)}

Código não destruído:

f=
{x->
  b=x.size();
  int[][]a=new int[b/2][b/2];
  for(i=0;i<b-1;i+=2) {
    for(j=0;j<b-1;j+=2) {
      z=x.toList().subList(i,i+2).collect{
        it.toList().subList(j,j+2)
      };
      a[(int)(i/2)][(int)(j/2)]=z[0][0]*z[1][1]-z[0][1]*z[1][0];
    }
  }
  a.size()==1
    ?
      a:f(a)
}
Urna de polvo mágico
fonte