最小成本块对角化


10

考虑二进制块对角矩阵,该矩阵在主对角线上具有1s的正方形块,而在其他各处均为0。让我们称此类矩阵为“有效”矩阵。

例如,以下是一些有效的4x4矩阵:

1 0 0 0     1 1 0 0     1 0 0 0     1 0 0 0     1 1 0 0    1 1 1 1
0 1 0 0     1 1 0 0     0 1 1 0     0 1 1 1     1 1 0 0    1 1 1 1
0 0 1 0     0 0 1 0     0 1 1 0     0 1 1 1     0 0 1 1    1 1 1 1
0 0 0 1     0 0 0 1     0 0 0 1     0 1 1 1     0 0 1 1    1 1 1 1

请注意,描述此类矩阵的另一种方法是,从左上角到右下角有一个正方形的1块链,触碰到另一个角,其他任何地方均为0。

相比之下,这是一些无效的4x4矩阵:

1 0 1 0     1 0 1 0     1 1 0 0     0 1 1 1     1 1 0 0    0 0 0 0
0 1 1 1     0 1 0 1     1 1 0 0     0 1 1 1     1 1 0 0    0 0 0 0
1 0 0 1     1 0 1 0     0 0 0 0     0 1 1 1     1 1 0 0    0 0 0 0
0 0 1 0     0 1 0 1     0 0 0 1     1 0 0 0     0 0 1 1    0 0 0 0

您将获得一个nn二元矩阵输入-什么是最低数量0,你会需要设置位1,以获得一个有效的矩阵?

您可以编写一个函数或程序,采用任何方便的字符串,列表或矩阵格式,它们表示0和1 的nby n矩阵(只要未经预处理即可)。行必须以某种方式清楚地分开,因此不允许使用一维位数组之类的格式。

这是,因此目标是最大程度地减少程序中的字节数。

例子

例如,如果输入是

0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 1

那么答案是5,因为您可以设置5 01来获得:

1 0 0 0 0
0 1 1 0 0
0 1 1 0 0
0 0 0 1 0
0 0 0 0 1

这是所需的最小数量。但是,如果输入是

0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

那么答案是24,因为右上角唯一的有效5x5矩阵1是所有1s 的矩阵。

测试用例

测试在这里表示为2D整数数组。

[[0]] -> 1
[[1]] -> 0
[[0,1],[0,0]] -> 3
[[1,0],[0,0]] -> 1
[[0,0,0],[0,1,0],[0,0,0]] -> 2
[[0,1,0],[0,0,0],[0,1,0]] -> 7
[[0,1,0],[1,0,0],[0,0,1]] -> 2
[[1,1,1],[1,1,1],[1,1,1]] -> 0
[[0,0,0,0],[0,0,1,0],[0,1,0,0],[0,0,0,0]] -> 4
[[0,0,1,0],[0,0,0,0],[0,0,0,0],[0,0,0,1]] -> 8
[[0,0,1,0],[0,0,0,0],[0,0,0,0],[0,0,1,0]] -> 14
[[0,0,1,0],[0,0,0,0],[0,0,0,0],[0,1,0,0]] -> 14
[[0,0,0,0,0],[0,0,0,0,0],[0,1,0,0,0],[0,0,0,0,1],[0,0,0,0,0]] -> 7
[[0,0,0,0,0],[0,0,0,0,0],[1,0,0,0,0],[0,0,0,0,1],[0,0,0,0,0]] -> 11
[[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,1]] -> 5
[[0,0,0,0,1],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]] -> 24
[[0,0,0,1,0],[0,0,0,0,1],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]] -> 23
[[0,1,0,0,0],[1,0,0,0,0],[0,0,1,0,0],[0,0,0,0,1],[0,0,0,1,0]] -> 4
[[0,1,1,1,0],[0,1,1,0,1],[0,1,1,1,0],[0,1,0,0,1],[0,0,0,0,0]] -> 14

笔记

Answers:


3

MATL46 43字节

nX^tQt:qZ^!tsb=Z)"@!"@1$l]@n$YdG-Q?6MG>zvX<

输入是一个以分号作为行分隔符的2D数组。例如,最后一个测试用例的输入是

[0,1,1,1,0;0,1,1,0,1;0,1,1,1,0;0,1,0,0,1;0,0,0,0,0]

在线尝试!验证所有测试用例(对代码进行少许修改以接受所有输入;结果在几秒钟后出现)

说明

令输入为N × N矩阵。该代码首先计算所有(N +1)个块大小的元组,这些元组产生适当的矩阵大小。例如,对于Ñ = 4元组是0 0 0 0 40 0 0 1 3,..., 4 0 0 0 0。对于每个元组,它使用这些块大小构建块对角矩阵。然后,它检查矩阵是否覆盖了1输入中的所有条目,如果是,请注意1输入中不存在的条目数。最终结果是所有获得的数量中的最小值。

nX^      % Implicit input  an N×N matrix. Get N
t        % Duplicate N
Qt:q     % Vector [0 1 ... N]
Z^       % Cartesian power. Gives 2D array
!ts      % Transpose, duplicate, sum of each column
b=       % Logical vector that equals true if the sum is N
Z)       % Filter columns according to that. Only keep columns that sum to N. Each 
         % column is the size of one block
"        % For each column
  @      %   Push that column
  "      %   For each entry of that column
    @    %     Push that entry
    1$l  %     Square matrix with that size, filled with 1
  ]      %   End
  @n     %   Column size. This is the number of blocks in the block-diagonal matrix
  $Yd    %   Build block-diagonal matrix from those blocks
  G-Q    %   Subtract input matrix element-wise, and add 1
  ?      %   If all entries are nonzero (this means each that entry that is 1 in the
         %   block-diagonal matrix is also 1 in the input matrix)
    6M   %   Push block-diagonal matrix again
    G>   %   For each entry, gives 1 if it exceeds the corresponding entry of the
         %   input, that is, if the block-diagonal matrix is 1 and the input is 0
    z    %   Number of 1 entries
    v    %   Concatenate vertically with previous values
    X<   %   Take minimum so far
         %   Implicit end
         % Implicit end
         % Implicit display

3

带有numpy的Python,102

from numpy import*
lambda M:sum(diff([k for k in range(len(M)+1)if(M|M.T)[:k,k:].any()-1])**2)-M.sum()

一种高效的算法。在对角线上找到可以分开块的“颈点”。它们的上,右,下和左全为0。最小的块是在颈部之间的那些。

??000
??000
00???
00???
00???

块的长度是连续颈点之间的差,因此它们的总面积为这些平方和的平方和。减去原始矩阵的总和即可得出从0到1所需的翻转次数。


2

Pyth,45个字节

-hSlMf@I.DRlQx1sQTms.b^+LsYN2d+0._ds.pM./lQss

艰巨的任务,所以很长。

在线尝试:演示测试套件

说明:

s.pM./lQ计算的所有整数分区len(matrix)ms.b^+LsYN2d+0._d将它们转换为坐标对。例如分区[1, 2, 2]5被转换成[[0,0], [1,1], [1,2], [2,1], [2,2], [3,3], [3,4], [4,3], [4,4]

f@I.DRlQx1sQT然后过滤完全与矩阵重叠的分区(.DRlQx1sQ计算矩阵中活动单元的所有坐标对)。

-hSlM...ss 计算剩余的每个分区的单元格,选择单元格最少的单元格,然后减去已经激活的单元格。


0

Matricks,180字节(非竞争)

Matricks是我最近创建的一种新的esolang,用于处理矩阵问题(例如此问题),它只有两种数据类型:浮点数和矩阵。它的功能尚未完全实现,仍然缺少许多操作(我不得不为此挑战添加一些功能)。无论如何,这是代码:

il=1:j3;:bdx;;;s1::L;j1;;
b{q:1;mgr:c;|gc:r;|(r=c)|(gr-1:c;|gr:c+1;)&(rec)|(gr+1:c;|gr:c-1;)&(cer):l:L;};z:(l-1)/2;B1;s1::g1:;-1;ig1:;=0:j2;:j1;;
s1::d{q:1;};;kg1:;-g:;;
kg:;*-1+1;

说明

第一部分,il=1:j3;:...;检查数组的大小是否为1。如果是,则跳转到最后一行kg:;*-1+1;,这是一个简单的0 <-> 1函数。

否则,它将继续其余的代码。bdx;;;将单元格0,0设置为当前总和,并s1::L;j1;在下一行的单元格中创建一个计数器。

下一行稍微复杂一点。这是一个运行n时间的循环,即n矩阵的大小。我将以第3个测试用例为例。当我们第一次到达第二行时,矩阵如下所示:

1 0 1
2 0 0

首先,我们进入矩阵理解{q:1;m...;}。这样就形成了对角线,并尽最大努力清除需要填写的0。所有这些操作都使用简单的布尔运算符完成。然后,将其添加到当前矩阵的前面,给出以下内容:

    V--data we want to keep
1 1 1 0 1 <-|
1 1 2 0 0 <-- old matrix

然后,我们使用切割旧矩阵z:(l-1)/2;,然后使用将整个矩阵向左旋转B1;。这样就为下一步准备了一个矩阵,如下所示:

1 1 1
2 1 1

最后,我们递减计数器,检查计数器,然后继续 ig1:;=0:j2;:j1;;

打破循环后,我们将找到新的总和,并使用来设置计数器的旧点s1::d{q:1;};;。最后,我们求差并返回kg1:;-g:;;k将当前数组设置为一个值,并且打印是隐式的。

...

如您所见,Matricks非常冗长,不是很好的高尔夫语言。但是,我想炫耀它。

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.