最小コストのブロック対角化


10

主対角線上に1の正方ブロックを持ち、その他の場所では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

あなたは与えられますnによってn入力としてバイナリ行列-最小数の何である0あなたがに設定する必要がありますビット1の有効な行列を得るためには?

(前処理されていない限り)0と1のnby n行列を表す便利な文字列、リスト、または行列形式で関数またはプログラムを記述できます。行は何らかの方法で明確に分離する必要があるため、ビットの1D配列のような形式は許可されません。

これはなので、プログラムのバイト数を最小限に抑えることが目標です。

たとえば、入力が

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ビットを設定することができるので、答えは5です1

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すべて1のsのマトリックスだからです。

テストケース

テストはここでは整数の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

ノート

回答:


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)タプルのブロックサイズを計算します。例えば、のためN = 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は、floatとmatriciesの2つのデータ型のみを使用して、マトリックスの問題(この問題など)に対処するために最近作成した新しい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かどうかを確認します。サイズが1の場合kg:;*-1+1;は、単純な0 <-> 1関数である最後の行にジャンプします。

それ以外の場合は、残りのコードを続行します。bdx;;;セル0,0を現在の合計に設定し、s1::L;j1;下の行のセルにカウンターを作成します。

次の行はもう少し複雑です。これは、実行されるループでn、回をn行列のサイズです。例として、3番目のテストケースを使用します。最初に2行目に到達すると、マトリックスは次のようになります。

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はかなり冗長であり、ゴルフ言語としてはあまり優れていません。しかし、まあ、私はそれを自慢したかったです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.