Composants fortement connectés

16

Deux sommets distincts dans un graphe orienté sont fortement connectés s'il y a un chemin dans le graphe l'un de l'autre. Un composant fortement connecté du graphe est un sous-ensemble du graphe tel que chaque paire de sommets distincts dans le sous-ensemble est fortement connectée, et l'ajout de sommets supplémentaires au sous-ensemble briserait cette propriété.

Votre défi consiste à séparer un graphique en ses composants fortement connectés. Plus précisément, vous devez générer tous les SCC dans le graphique.

E / S:

En entrée, vous pouvez utiliser une liste de bords dirigés, une liste d'adjacence, une matrice d'adjacence ou tout autre format d'entrée raisonnable. Demandez si vous n'êtes pas sûr. Vous pouvez supposer que le graphique n'a pas de sommets totalement déconnectés et qu'il n'y a pas de bords autonomes, mais vous ne pouvez pas émettre d'autres hypothèses. Vous pouvez également éventuellement prendre la liste des sommets en entrée, ainsi que le nombre de sommets.

En sortie, vous devez soit donner un partitionnement des sommets, comme une liste de listes de sommets, où chaque sous-liste est un composant fortement connecté, soit un étiquetage des sommets, où chaque étiquette correspond à un composant différent.

Si vous utilisez un étiquetage, les étiquettes doivent être soit des sommets, soit une séquence consécutive d'entiers. C'est pour éviter de transférer le calcul dans les étiquettes.

Exemples:

Ces exemples prennent des listes d'arêtes, où chaque arête est dirigée de la première entrée vers la deuxième entrée, et des partitions de sortie. Vous êtes libre d'utiliser ce format ou un autre.

L'entrée est sur la première ligne, la sortie est sur la deuxième ligne.

[[1, 2], [2, 3], [3, 1], [1, 4]]
[[1, 2, 3], [4]]

[[1, 2], [2, 3], [3, 4]]
[[1], [2], [3], [4]]

[[1, 2], [2, 1], [1, 3], [2, 4], [4, 2], [4, 3]]
[[1, 2, 4], [3]]

[[1, 2], [2, 3], [2, 5], [2, 6], [3, 4], [3, 7], [4, 3], [4, 8], [5, 1], [5, 6], [6, 7], [7, 6], [8, 7], [8, 4]]
[[1, 2, 5], [3, 4, 8], [6, 7]]

Notation et restrictions:

Les failles standard sont interdites, comme toujours. De plus, les modules intégrés qui traitent spécifiquement des composants fortement connectés sont interdits.

Les solutions devraient fonctionner en moins d'une heure sur les exemples fournis. (Ceci est destiné à empêcher les solutions exponentielles lentes, et rien d'autre.)

C'est le golf de code. Le moins d'octets gagne.

isaacg
la source
Quelle est la flexibilité des étiquettes que nous attribuons à un composant connecté? Par exemple, la liste des indices de sommet dans ce composant serait-elle une étiquette valide?
xnor
@xnor Entièrement flexible. Doit correspondre via des tests d'égalité / des chaînes identiques.
isaacg
Notre format d'entrée de graphique peut-il également contenir le nombre de sommets et / ou une liste d'étiquettes de sommets?
xnor
@xnor Oui aux deux. Je vais le modifier.
isaacg
Dans le dernier cas de test, j'obtiens qui 8n'est pas dans un composant avec [3,4]car il ne peut pas seulement chacun 6et 7(ni l'un ni l'autre ne l'atteindre).
xnor

Réponses:

7

Python 2 utilisant numpy, 71 62 octets

import numpy
def g(M,n):R=(M+M**0)**n>0;print(R&R.T).argmax(0)

Prend l'entrée comme une numpymatrice représentant l'adjacence et le nombre de nœuds. Produit une sortie sous forme de numpymatrice de lignes qui étiquette chaque sommet par le plus petit nombre de sommets de son composant.

Pour une matrice d'adjacence M, la puissance de la matrice M**ncompte le nombre de nchemins d'étape de chaque sommet de début à chaque sommet de fin. L'ajout de l'identité à Mvia M+M**0modifie la matrice d'adjacence pour ajouter une boucle automatique à chaque bord. Donc, (M+M**0)**ncompte au maximum les chemins de longueur n(avec redondance).

Étant donné que tout chemin a une longueur au plus n, le nombre de nœuds, tout point d' (i,j)où le sommet jpeut être atteint icorrespond à une entrée positive de (M+M**0)**n. La matrice d'accessibilité est alors R=(M+M**0)**n>0, où les >0travaux en entrée.

Le calcul de l'entrée andcomme R&R.T, où R.Test la transposition, donne alors une matrice indiquant les paires de sommets mutuellement accessibles. C'est la iligne est un vecteur indicateur pour les sommets dans le même composant fortement connecté que lui. Prendre son argmaxde chaque ligne donne l'indice du premier True, qui est l'indice du plus petit sommet de sa composante.

xnor
la source
4

JavaScript (ES6), 125 octets

a=>a.map(([m,n])=>(e[m]|=1<<n|e[n],e.map((o,i)=>o&1<<m?e[i]|=e[m]:0)),e=[])&&e.map((m,i)=>e.findIndex((n,j)=>n&1<<i&&m&1<<j))

Prend une liste de paires dirigées comme argument, tandis que le résultat est un tableau pour chaque sommet donnant le premier sommet fortement connecté à lui, ce qui, à mon avis, compte comme un étiquetage valide. Par exemple, avec l'entrée [[1, 2], [2, 3], [2, 5], [2, 6], [3, 4], [3, 7], [4, 3], [4, 8], [5, 1], [5, 6], [6, 7], [7, 6], [8, 7], [8, 4]]qu'elle renvoie [, 1, 1, 3, 3, 1, 6, 6, 3](il n'y a pas de sommet 0; les sommets 1, 2 et 5 ont l'étiquette 1; 3, 4 et 8 ont l'étiquette 3 tandis que 6 et 7 ont l'étiquette 6).

Neil
la source
4

MATL , 26 22 octets

tnX^Xy+HMY^gt!*Xu!"@f!

Cela utilise la même approche que la réponse de @ xnor .

Fonctionne dans la version actuelle (15.0.0) de la langue.

L'entrée est la matrice d'adjacence du graphique, avec des lignes séparées par des points-virgules. Les premier et dernier cas de test sont

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

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

Essayez-le en ligne!

t     % implicitly input adjacency matrix. Duplicate
n     % number of elements
X^    % square root
Xy    % identity matrix of that size
+     % add to adjacency matrix
HM    % push size again
Y^    % matrix power
g     % convert to logical values (0 and 1)
t!*   % multiply element-wise by transpose matrix
Xu    % unique rows. Each row is a connected component
!     % transpose
"     % for each column
  @   %   push that column
  f!  %   indices of nonzero elements, as a row
      % end for each. Implicitly display stack contents
Luis Mendo
la source
3

Pyth, 13 octets

.gu+Gs@LQG.{k

Démonstration , Suite de tests

L'entrée est une liste d'adjacence, représentée comme un dictionnaire qui mappe les sommets à la liste des sommets auxquels elle a des arêtes (ses voisins dirigés). La sortie est une partition.

L'essence du programme est que nous trouvons l'ensemble des sommets qui sont accessibles à partir de chaque sommet, puis regroupons les sommets par ces ensembles. Deux sommets dans le même SCC ont le même ensemble de sommets accessibles depuis eux, car chacun est accessible depuis l'autre, et l'accessibilité est transitive. Tous les sommets de différents composants ont des ensembles accessibles différents, car aucun des ensembles ne contient l'autre.

Explication du code:

.gu+Gs@LQG.{k
                  Implicit: Q is the input adjacency list.
.g           Q    Group the vertices of Q by (Q is implicit at EOF)
  u       .{k     The fixed point of the following function, 
                  starting at the set containing just that vertex
   +G             Add to the set
     s            The concatenation of
      @LQG        Map each prior vertex to its directed neighbors
isaacg
la source