Bien, entonces en la clasificación topológica dependiendo de los datos de entrada, generalmente hay múltiples soluciones correctas para qué orden el gráfico puede ser "procesado" para que todas las dependencias entren antes que los nodos que son "dependientes" de ellas. Sin embargo, estoy buscando una respuesta ligeramente diferente:Clasificación Topológica con Agrupación
Supongamos los siguientes datos: a -> b
y c -> d
(a
debe venir antes y b
c
debe venir antes d
).
Con solo estas dos limitaciones, tenemos múltiples soluciones candidatas: (a b c d
, a c d b
, c a b d
, etc.). Sin embargo, estoy buscando crear un método para "agrupar" estos nodos de modo que después del procesamiento de un grupo, todas las entradas en el siguiente grupo tengan sus dependencias atendidas. Para los supuestos datos anteriores, estaría buscando una agrupación como (a, c) (b, d)
. Dentro de cada grupo, no importa qué orden se procesen los nodos (a
antes del c
o b
antes del d
, etc. y viceversa) siempre que el grupo 1 (a, c)
finalice antes de que se procese alguno del grupo 2 (b, d)
.
El único inconveniente adicional sería que cada nodo debería estar en el primer grupo posible. Considerar los siguientes:
a -> b -> c
d -> e -> f
x -> y
Un esquema de agrupación de (a, d) (b, e, x) (c, f, y)
sería técnicamente correcto porque x
es antes y
, una solución más óptima sería (a, d, x) (b, e, y) (c, f)
porque tener x
en el grupo 2 implica que x
era dependiente en algún nodo del grupo 1.
¿Alguna idea sobre cómo hacer esto?
EDIT: Creo que logré unir algunos códigos de solución. ¡Gracias a todos los que ayudaron!
// Topological sort
// Accepts: 2d graph where a [0 = no edge; non-0 = edge]
// Returns: 1d array where each index is that node's group_id
vector<int> top_sort(vector< vector<int> > graph)
{
int size = graph.size();
vector<int> group_ids = vector<int>(size, 0);
vector<int> node_queue;
// Find the root nodes, add them to the queue.
for (int i = 0; i < size; i++)
{
bool is_root = true;
for (int j = 0; j < size; j++)
{
if (graph[j][i] != 0) { is_root = false; break; }
}
if (is_root) { node_queue.push_back(i); }
}
// Detect error case and handle if needed.
if (node_queue.size() == 0)
{
cerr << "ERROR: No root nodes found in graph." << endl;
return vector<int>(size, -1);
}
// Depth first search, updating each node with it's new depth.
while (node_queue.size() > 0)
{
int cur_node = node_queue.back();
node_queue.pop_back();
// For each node connected to the current node...
for (int i = 0; i < size; i++)
{
if (graph[cur_node][i] == 0) { continue; }
// See if dependent node needs to be updated with a later group_id
if (group_ids[cur_node] + 1 > group_ids[i])
{
group_ids[i] = group_ids[cur_node] + 1;
node_queue.push_back(i);
}
}
}
return group_ids;
}
Parece que solo quieres un grupo "codicioso". Encuentra todos los nodos que pueden estar en el primer grupo. Luego encuentre todos los nodos que puedan estar en el segundo grupo, etc., hasta que no queden nodos no asignados. – aschepler
Gracias por publicar su solución, pero ¿podría describir mejor el formato de entrada esperado? Tal vez con un ejemplo? – mpen
@mpen - La solución que publiqué espera una matriz de adyacencia vectorial 2D. Incluiría el formato de entrada original, pero esta pregunta tiene casi 6 años y desde entonces he extraviado el código original. –