Determinante ricorsivo 2x2


17

Il determinante di una matrice 2 per 2

a b
c d

è dato da ad - bc.

Data una matrice di cifre con dimensioni 2 n per 2 n , n ≥ 1, emette il risultato ottenuto calcolando ricorsivamente il determinante di ciascun sottoblocco 2 per 2 fino a raggiungere un singolo numero.

Ad esempio, dato l'input

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

Dopo un passaggio, otteniamo:

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

E ripetendo ancora una volta, otteniamo:

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

Quindi, l'output dovrebbe essere -1430.

Regole

  • Gli elementi della matrice saranno sempre numeri interi a una cifra, ovvero da 0 a 9.
  • È possibile accettare input in qualsiasi elenco o formato stringa conveniente, purché non venga eseguita la preelaborazione dei dati. Poiché la matrice è sempre quadrata, è possibile prendere input come un singolo elenco 1D anziché un elenco 2D, se lo si desidera.
  • L'input può essere tramite input di funzione, STDIN, argomento della riga di comando o alternativa più vicina.
  • L'output deve essere un singolo numero intero per funzionare output, STDOUT o alternativa più vicina. Non è possibile generare l'intero numero intero in un elenco o matrice.
  • È possibile utilizzare i metodi di manipolazione determinante e matrice incorporati se la propria lingua sembra supportarli.
  • Il tuo algoritmo deve funzionare in teoria per qualsiasi input valido.
  • Si applicano le regole standard del .

Casi test

I seguenti casi di test sono indicati come elenchi in stile 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

(Grazie a @ MartinBüttner per l'aiuto in questa sfida)


3
Curiosità: ho fatto alcuni esperimenti su questo e c'è un numero sorprendentemente grande di matrici binarie con determinante ricorsivo diverso da zero. Per le dimensioni 2x2, 4x4, 8x8, 16x16, otteniamo 6, 16488, 2229617029168687104, 3349795881591711813037585032680117995553655026185547430764970842694019448832 matrici con determinante diverso da zero, corrispondente al 37,5%, 2,858, 12,18
Martin Ender,

@ MartinBüttner: ottengo 6, 22560, 10160459763342013440, ... che corrispondono a A055165 .
Charles,

@Charles strano, controllerò il mio codice
Martin Ender,

@ MartinBüttner: forse stiamo solo calcolando due cose diverse?
Charles,

@Charles Considera la matrice [1,0,1,0;1,1,1,1;1,1,1,1;0,0,0,1]. Il determinante completo è zero poiché ha due righe identiche. Questa è quindi una matrice 4 × 4 singolare (che significa non invertibile), quindi non è conteggiata da A055165. Tuttavia, il determinante "ricorsivo" discusso qui è 1*1-1*0==1. Nella direzione opposta, la matrice [0,0,0,1;1,0,0,0;0,1,0,0;0,0,1,0]ha un determinante "ricorsivo" 0*0-0*0==0. Tuttavia, il suo determinante completo deve essere diverso da zero perché le sue righe sono solo le righe della matrice identità in un altro ordine; ed è conteggiato da A055165.
Jeppe Stig Nielsen,

Risposte:


8

J, 21 25 byte

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

Ad ogni passaggio tagliamo la matrice a 2 per 2 e calcoliamo ciascuna determinante risultante nella matrice di input della fase successiva. Ripetiamo questo processo fino a quando il risultato non cambia (l'elemento finale è il determinante stesso). Convertiamo il risultato finale in uno scalare con0{0{ .

Provalo online qui.


Ho provato a usare la funzione di piastrellatura di Cut per fare questo, ma non sono riuscito a giocarci fino alla tua versione. 29 byte: (2 2$2)&(-/ .*;._3^:(2^.#@])) provalo online!
Giona,

4

Mathematica, 52 40 byte

Grazie a Martin Büttner per aver salvato 12 byte.

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

Spiegazione

BlockMap[f,expr,n]diviso exprin elenchi di dimensioni ne mappa fsu ogni elenco. BlockMap[Det,#,{2,2}]&dividere l'array di input in blocchi 2 * 2 e calcolare i relativi determinanti.


Caso di prova

%[{{3,1,4,1},{5,9,2,6},{5,3,5,8},{9,7,9,3}}]
(* -1430 *)

1
Ho scritto un'implementazione di riferimento in Mathematica mentre discutevo dell'idea di sfida con Sp3000 ed è di 40 byte. È abbastanza simile al tuo, quindi ti darò un po 'di tempo per trovarlo tu stesso, se vuoi. :)
Martin Ender,

@ MartinBüttner ho fallito. :(
njpipeorgan,

1
Puoi evitare il [[1,1]]con Tre il Nestcon //.:Tr[#//.l:{_,__}:>BlockMap[Det,l,{2,2}]]&
Martin Ender,

@ MartinBüttner In realtà, mi è venuta in mente //. idea durante la lettura della risposta in J, ma bloccato nel trovare un buon modo per abbinare l'array. : P
njpipeorgan,

sentiti libero di usare la mia soluzione per aggiornare la tua risposta
Martin Ender,

3

Gelatina, 20 17 byte

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

Provalo online! oppure verifica tutti i casi di test contemporaneamente .

Come funziona

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.

2

Haskell , 93 86 byte

EDIT: Grazie a @Laikoni per averlo abbreviato di ben 7 byte!

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]

Non sapevo che avresti potuto mettere una dichiarazione let prima del = e non mi sono mai abituato a quegli operatori di monade. Grazie ancora @Laikoni

Vecchia versione:

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]

Provalo online!

Questa è una funzione che ricorre su se stessa in due modi diversi. Innanzitutto la corrispondenza del modello cattura il case base: una matrice 2x2 e fa il calcolo. Uso questo per fare il calcolo nel caso ricorsivo chiamando la funzione con una matrice 2x2 che ho generato che contiene le soluzioni ricorsive. Quella matrice viene generata ripetendo due volte su una serie di funzioni che ciascuna suddivide a metà un elenco. Lo applico alle righe con una semplice chiamata e lo applico alle colonne usandomap .


Invece di where h=length m`div`2;l=[take h,drop h], puoi usare f m|let l=[take,drop]<*>[length m`div`2]=. map b mpuò essere b<$>me [f$a$b<$>m|a<-l]può essere ulteriormente abbreviato in f.($b<$>m)<$>l. Complessivamente 86 byte: [ tio.run/… Provalo online!]
Laikoni

1

Python, 166 byte

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]

Questo supera tutti i casi di test forniti. m deve essere un array 2D (come nei casi di test), g seleziona la matrice secondaria.


1

Pyth, 26

M-F*VG_HhhumgMCcR2dcG2llQQ

Test Suite

Questo ha due parti: M-F*VG_Hridefinisce la funzione gper calcolare il determinante di una matrice due per due. Ciò consente di risparmiare byte anche se lo utilizziamo solo una volta perché decomprime le due righe.

L'altra parte è una grande dichiarazione di riduzione che chiamiamo log_2( len( input() ) )tempi. Sfortunatamente, eseguendo un passo nella riduzione su una matrice 1 per 1, il risultato viene racchiuso in un elenco, quindi non otteniamo un punto fisso. La riduzione consiste principalmente nel dividere la matrice per ottenere matrici 2 per 2 e quindi applicarle g.


1

MATL , 26 30 byte

`tnX^teHHhZC2Ih2#Y)pwp-tnq

L'input è un array 2D con righe separate da ;, ovvero

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

Provalo 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

1

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

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

Provalo online!

Prende l'input come un elenco di numeri separati da spazi.


0

ES6, 91 byte

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

Soluzione ricorsiva semplice.


0

R , 111 byte

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

Provalo online!

Accetta input come una matrice R (che viene convertita dalla funzione nell'intestazione).


0

Groovy, 221 189 byte (A questo punto, avrebbe potuto usare 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)}

Vecchia versione scadente, che potrebbe anche essere Java (221 byte):

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

Codice non golfato:

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