Рекурсивна 2х2 детермінанта


17

Визначник матриці 2 на 2

a b
c d

дається ad - bc.

Дано матрицю цифр розмірами 2 n на 2 n , n ≥ 1, виведіть результат, отриманий шляхом рекурсивного обчислення визначника кожного 2 на 2 підблоку, поки ми не досягнемо єдиного числа.

Наприклад, з урахуванням введення

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

Після одного кроку ми отримуємо:

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

І ще раз повторившись, ми отримаємо:

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

Отже, вихід повинен бути -1430.

Правила

  • Елементи матриці завжди будуть одноцифровими цілими числами, тобто від 0 до 9.
  • Ви можете приймати дані в будь-якому зручному списку або рядковому форматі, доки не буде виконано попередню обробку даних. Оскільки матриця завжди квадратна, ви можете приймати введення як єдиний 1D список замість 2D списку, якщо бажаєте.
  • Введення може здійснюватися через функцію введення, STDIN, аргумент командного рядка або найближчу альтернативу.
  • Вихід повинен бути одним цілим числом для функціонування виводу, STDOUT або найближчої альтернативи. Ви не можете вивести єдине ціле число у списку чи матриці.
  • Ви можете використовувати вбудовані методи детермінантної та матричної маніпуляцій, якщо ваша мова підтримує їх.
  • Ваш алгоритм повинен теоретично працювати для будь-якого дійсного введення.
  • Діють стандартні правила .

Тестові справи

Наступні тестові випадки наведені як списки стилів 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

(Дякую @ MartinBüttner за допомогу у вирішенні цього виклику)


3
Веселий факт: я провів кілька експериментів з цього питання, і є напрочуд велика кількість двійкових матриць з ненульовим рекурсивним визначником. Для розмірів 2х2, 4х4, 8х8, 16х16 отримуємо 6, 16488, 2229617029168687104, 3349795881591711813037585032680117995553655026185547430764970842694019448832 матриці з ненульовим визначенням, що відповідає відповідно 37,5%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 0,25%, 25,5%;
Мартін Ендер

@ MartinBüttner: я отримую 6, 22560, 10160459763342013440, ... що відповідає A055165 .
Чарльз

@Charles дивним, я перевірю свій код
Мартін Ендер

@ MartinBüttner: Можливо, ми просто обчислюємо дві різні речі?
Чарльз

@Charles Розгляньте матрицю [1,0,1,0;1,1,1,1;1,1,1,1;0,0,0,1]. Повний визначник його дорівнює нулю, оскільки він має два однакових рядки. Таким чином, ця є єдиною (означає неперевернуту) матрицею 4 × 4, тому її не рахують за A055165. Однак "рекурсивний" детермінант, про який йде мова, є1*1-1*0==1 . У зворотному напрямку матриця [0,0,0,1;1,0,0,0;0,1,0,0;0,0,1,0]має "рекурсивний" визначник 0*0-0*0==0. Однак його повний визначник повинен бути не нульовим, оскільки його рядки - це лише рядки матриці ідентичності в іншому порядку; і він рахується A055165.
Джеппе Стіг Нільсен

Відповіді:


8

J, 21 25 байт

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

Використання:

   ]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

На кожному кроці ми розрізаємо матрицю до 2-х по 2 і обчислюємо кожен визначальний результат, що призводить до введення матриці наступного кроку. Повторюємо цей процес, поки результат не зміниться (кінцевий елемент є самим визначальним фактором). Перетворюємо кінцевий результат у скалярний за допомогою 0{0{.

Спробуйте його онлайн тут.


Спробував це зробити, використовуючи функцію плитки Кат, але не зміг пройти в гольф, наскільки це було у вашій версії. 29 байт: (2 2$2)&(-/ .*;._3^:(2^.#@])) Спробуйте в Інтернеті!
Йона

4

Математика, 52 40 байт

Завдяки Мартіну Бюттнеру за збереження 12 байт.

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

Пояснення

BlockMap[f,expr,n]розділити exprна підлістики за розміром nі відобразити fна всіх підспісах.BlockMap[Det,#,{2,2}]&розділити вхідний масив на 2 * 2 блоки та обчислити їх детермінанти.


Тестовий випадок

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

1
Я написав референтну реалізацію в Mathematica, обговорюючи складну ідею з Sp3000, і це 40 байт. Це дуже схоже на ваше, тому я дам вам трохи часу, щоб знайти його самостійно, якщо вам подобається. :)
Мартін Ендер

@ MartinBüttner Я не зміг. :(
njpipeorgan

1
Ви можете уникнути [[1,1]]з Trі Nestразом із //.:Tr[#//.l:{_,__}:>BlockMap[Det,l,{2,2}]]&
Мартін Ендер

@ MartinBüttner Власне, я придумав //. ідея, читаючи відповідь в J, але застрягла в пошуку хорошого способу зіставити масив. : P
njpipeorgan

не соромтеся використовувати моє рішення, щоб оновити свою відповідь
Мартін Ендер

3

Желе, 20 17 байт

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

Спробуйте в Інтернеті! або перевірити всі тестові справи одразу .

Як це працює

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

Хаскелл , 93 86 байт

EDIT: Дякую @Laikoni за скорочення цього цілих 7 байт!

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]

Я не знав, що ти можеш поставити дозволу перед «=» і я ніколи не звик до цих операторів монади. Ще раз дякую @Laikoni

Стара версія:

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]

Спробуйте в Інтернеті!

Це функція, яка повторюється сама по собі двома різними способами. Спочатку відповідність шаблону вловлює базовий випадок: матриця 2x2, і вона робить розрахунок. Я використовую це для обчислення в рекурсивному випадку, викликаючи функцію за допомогою матриці 2x2, яку я генерую, і в ній є рекурсивні рішення. Ця матриця генерується шляхом повторної ітерації в масиві функцій, які кожен перетинає список навпіл. Я застосовую його до рядків простим викликом і застосовую до стовпців за допомогою map.


Замість цього where h=length m`div`2;l=[take h,drop h]можна використовувати f m|let l=[take,drop]<*>[length m`div`2]=. map b mможе бути b<$>m, і [f$a$b<$>m|a<-l]може бути додатково скорочено до f.($b<$>m)<$>l. Всього 86 байт: [ tio.run/… Спробуйте в Інтернеті!]
Лайконі

1

Пітон, 166 байт

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]

Це проходить усі надані тестові випадки. m має бути двовимірним масивом (як у тестових випадках), g вибирає підматрицю.


1

Піта, 26

M-F*VG_HhhumgMCcR2dcG2llQQ

Тестовий сюїт

Він має дві частини: M-F*VG_Hпереосмислює функцію gобчислення визначника матриці два на дві. Це економить байти, хоча ми використовуємо його лише один раз, оскільки він розпаковує два ряди.

Інша частина - це велике скорочення, яке ми називаємо log_2( len( input() ) )часом. На жаль, виконання кроку скорочення на матриці 1 на 1 призводить до того, що результат буде зафіксовано у списку, тому ми не отримуємо фіксованої точки. Зменшення в основному є просто розщепленням матриці, щоб отримати матриці 2 на 2, а потім застосувати g.


1

MATL , 26 30 байт

`tnX^teHHhZC2Ih2#Y)pwp-tnq

Вхід - це 2D масив із рядками, розділеними ;, тобто

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

Спробуйте в Інтернеті!

`             % 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


0

ES6, 91 байт

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

Безпосередньо рекурсивне рішення.



0

Groovy, 221 189 байт (На даний момент я міг би використовувати 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)}

Стара версія шаленої, яка також може бути Java (221 байт):

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

Невикористаний код:

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)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.