递归2x2行列式


17

2 x 2矩阵的行列式

a b
c d

由给出ad - bc

给定尺寸为2 n x 2 n的数字矩阵,n≥1,输出通过递归计算每个2 x 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
有趣的事实:我对此进行了一些实验,并且意外地有大量具有非零递归行列式的二进制矩阵。对于大小为2x2、4x4、8x8、16x16的矩阵,我们得到6,16488,2229617029168687104,3349795881591711813037585032680117995553655026185547430764970842694019448848832具有非零行列式的矩阵,分别对应于37.5%,25.1587%,12.0868%,2.82294%。
Martin Ender

@MartinBüttner:我得到6,22560,10160459763342013440,...匹配A055165
查尔斯

@查尔斯·奇,我将检查我的代码
Martin Ender

@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计数。
杰普·斯蒂格·尼尔森

Answers:


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{

在这里在线尝试。


尝试使用Cut的平铺功能执行此操作,但无法将其打高尔夫球至您的版本。29个字节:(2 2$2)&(-/ .*;._3^:(2^.#@])) 在线尝试!
约拿(Jonah)

4

Mathematica,52个 40字节

感谢MartinBüttner节省了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
在讨论Sp3000及其40字节的挑战概念时,我在Mathematica中编写了参考实现。不过,它与您的非常相似,因此,如果您愿意,我会给您一些时间自行查找。:)
Martin Ender

@MartinBüttner我失败了。:(
njpipeorgan

1
您可以避免[[1,1]]with Tr和the Nestwith //.Tr[#//.l:{_,__}:>BlockMap[Det,l,{2,2}]]&
Martin Ender

@MartinBüttner实际上,我想到了//。阅读J语言中的答案时会想到一个主意,但始终坚持寻找匹配数组的好方法。:P
njpipeorgan

随时使用我的解决方案来更新您的答案
Martin Ender

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

Haskell93 86字节

编辑:感谢@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]

我不知道您可以在=之前放一个let语句,而且我从未习惯过这些monad运算符。再次感谢@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/…在线尝试!]
Laikoni '17

1

Python,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必须是2D数组(如在测试用例中一样),g选择子矩阵。


1

佩斯,26

M-F*VG_HhhumgMCcR2dcG2llQQ

测试套件

这包括两个部分:M-F*VG_H重新定义功能g以计算二矩阵的行列式。即使我们只使用一次它也可以节省字节,因为它解压缩了两行。

另一部分是我们称为log_2( len( input() ) )时间的大型reduce语句。不幸的是,对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

1

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

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

在线尝试!

将输入作为空格分隔数字的列表。


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

R,111字节

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

在线尝试!

将输入作为R矩阵(由标头中的函数转换)。


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

旧的cr脚版本,也可能是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)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.