Diagonalisation de bloc à coût minimum

10

Considérez les matrices diagonales de blocs binaires qui ont des blocs carrés de 1 sur la diagonale principale et sont 0 partout ailleurs. Appelons de telles matrices des matrices "valides".

Par exemple, voici quelques matrices 4x4 valides:

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

Notez qu'une autre façon de décrire de telles matrices est qu'il existe une chaîne de blocs carrés 1 du haut à gauche au bas à droite, touchant coin à coin, et partout ailleurs est 0.

Par contraste, voici quelques matrices 4x4 invalides:

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

Vous recevrez une npar nmatrice binaire en entrée - quel est le nombre minimum de 0morceaux que vous aurez besoin de mettre à 1afin d'obtenir une matrice valide?

Vous pouvez écrire une fonction ou un programme prenant n'importe quelle chaîne, liste ou format matriciel pratique représentant une nsous- nmatrice de 0 et 1 (tant qu'il n'est pas prétraité). Les lignes doivent être clairement séparées d'une certaine manière, donc les formats comme un tableau 1D de bits ne sont pas autorisés.

Il s'agit de , donc l'objectif est de minimiser le nombre d'octets dans votre programme.

Exemples

Par exemple, si l'entrée est

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

alors la réponse est 5, puisque vous pouvez définir cinq 0bits 1pour obtenir:

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

et c'est le nombre minimum requis. Cependant, si l'entrée était

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

alors la réponse est 24, puisque la seule matrice 5x5 valide où le coin supérieur droit 1est la matrice de tous les 1s.

Cas de test

Les tests sont représentés ici sous la forme d'un tableau 2D d'entiers.

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

Remarques

Sp3000
la source

Réponses:

3

MATL , 46 43 octets

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

L'entrée est un tableau 2D avec un point-virgule comme séparateur de ligne. Par exemple, l'entrée du dernier scénario de test est

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

Essayez-le en ligne! Ou vérifiez tous les cas de test (code légèrement modifié pour prendre toutes les entrées; les résultats apparaissent après quelques secondes)

Explication

Soit l'entrée une matrice N × N. Le code calcule d'abord tous les ( N +1) -tuples de tailles de blocs qui produisent la taille de matrice appropriée. Par exemple, pour N = 4 tuples sont 0 0 0 0 4, 0 0 0 1 3..., 4 0 0 0 0. Pour chaque tuple, il construit la matrice diagonale de bloc avec ces tailles de bloc. Il vérifie ensuite si la matrice couvre toutes les 1entrées de l'entrée et, dans l'affirmative, prend note du nombre d' 1entrées qui n'étaient pas présentes dans l'entrée. Le résultat final est le minimum de tous les nombres obtenus.

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
Luis Mendo
la source
3

Python avec numpy, 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()

Un algorithme efficace. Trouve les "points du cou" sur la diagonale qui peuvent séparer les blocs. Ceux-ci ont tous les 0 au-dessus et à droite, ainsi qu'en dessous et à gauche. Les blocs minimaux sont ceux entre les points du cou.

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

La longueur d'un bloc est la différence entre des points de cou consécutifs, donc leur surface totale de la somme des carrés de ceux-ci. La soustraction de la somme de la matrice d'origine donne alors le nombre de flips nécessaires de 0 à 1.

xnor
la source
2

Pyth, 45 octets

[email protected]^+LsYN2d+0._ds.pM./lQss

Tâche difficile, donc c'est assez long.

Essayez-le en ligne: démonstration ou suite de tests

Explication:

s.pM./lQcalcule toutes les partitions entières de len(matrix). ms.b^+LsYN2d+0._dles convertit en paires de coordonnées. Par exemple, la partition [1, 2, 2]de 5est convertie en [[0,0], [1,1], [1,2], [2,1], [2,2], [3,3], [3,4], [4,3], [4,4].

[email protected]puis filtre les partitions qui chevauchent complètement la matrice ( .DRlQx1sQcalcule toutes les paires de coordonnées des cellules actives de la matrice).

-hSlM...ss compte les cellules de chaque partition restante, choisit celle avec le moins de cellules et soustrait les cellules déjà actives.

Jakube
la source
0

Matricks , 180 octets (sans concurrence)

Matricks est un nouvel esolang que j'ai créé très récemment pour traiter les problèmes de matrice (comme celui-ci), en n'ayant que 2 types de données: flottants et matricies. Il n'est pas encore entièrement présenté et a encore beaucoup d'opérations manquantes (j'ai dû ajouter des fonctionnalités pour ce défi). Quoi qu'il en soit, voici le code:

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;

Explication

La première partie, il=1:j3;:...;vérifie si le tableau est de taille 1. S'il l'est, il saute à la dernière ligne kg:;*-1+1;, qui est une 0 <-> 1fonction simple .

Sinon, il continue avec le reste du code. bdx;;;définit la cellule 0,0sur la somme actuelle et s1::L;j1;crée un compteur dans la cellule de la ligne ci-dessous.

La ligne suivante est un peu plus compliquée. Il est une boucle qui court ntemps, nétant la taille de la matrice. Je vais utiliser le 3e cas de test comme exemple. Lorsque nous arrivons à la deuxième ligne, la matrice ressemble à ceci:

1 0 1
2 0 0

Tout d'abord, nous entrons dans la compréhension matricielle {q:1;m...;}. Cela fait la diagonale et fait de son mieux pour nettoyer 0 qui doit être rempli. Tout cela est accompli en utilisant de simples opérateurs booléens. Ensuite, nous l'ajoutons à la matrice actuelle, donnant ceci:

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

Ensuite, nous coupons de l'ancienne matrice en utilisant z:(l-1)/2;, et tournons la matrice entière vers la gauche en utilisant B1;. Cela nous donne une matrice prête pour la prochaine itération, ressemblant à:

1 1 1
2 1 1

Enfin, nous décrémentons le compteur, le vérifions et continuons avec ig1:;=0:j2;:j1;;

Une fois la boucle rompue, nous trouvons la nouvelle somme et définissons l'ancien emplacement du compteur avec s1::d{q:1;};;. Enfin, nous prenons la différence et revenons kg1:;-g:;;. kdéfinit le tableau actuel sur une valeur et l'impression est implicite.

...

Comme vous pouvez le voir, Matricks est assez bavard et n'est pas une très bonne langue de golf. Mais bon sang, je voulais le montrer.

Bleu
la source