Algoritmo de clasificación topológica y ejemplos

clasificación topológica

Ordenar topológicamente un gráfico acíclico dirigido (DAG para abreviar) G es organizar todos los vértices en G en una secuencia lineal, de modo que cualquier par de vértices u y v en el gráfico, si el borde <u, v>∈ E( G), entonces u aparece antes de v en la secuencia lineal. Por lo general, dicha secuencia lineal se denomina secuencia que satisface el orden topológico (Orden topológico), denominada secuencia topológica. En pocas palabras, un orden total en un conjunto se obtiene a partir de un orden parcial en un determinado conjunto, y esta operación se denomina clasificación topológica.

Pasos

Para gráficos acíclicos dirigidos, el algoritmo de clasificación topológica para construir secuencias topológicas ejecuta principalmente los siguientes dos pasos en un bucle hasta que no hay vértice con un grado de entrada de 0.
(1) Seleccione un vértice con un grado de entrada de 0 y envíelo;
(2) Elimine este vértice y todos los bordes salientes de la red.
Después de que finaliza el ciclo, si el número de vértices de salida es menor que el número de vértices en la red, entonces genera la información del "bucle", de lo contrario, la secuencia de vértices de salida es una secuencia topológica.

ejemplo

Ritual 207 Horario del plan de estudios

búsqueda en amplitud

Generar una ordenación topológica secuencialmente es un tipo de pensamiento positivo.
Usamos una cola para la búsqueda en amplitud. Inicialmente, todos los nodos con un grado de entrada de 0 se colocan en la cola, son los nodos superiores que se pueden ordenar topológicamente y el orden relativo entre ellos es irrelevante.
En cada paso de la búsqueda primero en anchura, eliminamos el nodo u al principio de la cola:

  • Ponemos u en la respuesta;
  • Elimine todos los bordes salientes de u, es decir, reduzca los grados de entrada de todos los nodos adyacentes de u en 1. Si el grado de entrada de un nodo vecino v se vuelve 0, entonces ponemos v en la cola.

Después de que termine el proceso de búsqueda primero en amplitud. Si los n nodos están incluidos en la respuesta, entonces hemos encontrado una ordenación topológica; de lo contrario, hay un ciclo en el gráfico y no hay una ordenación topológica.

class Solution {
    
    
private:
    vector<vector<int>> edges;
    vector<int> indeg;

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
    
        edges.resize(numCourses);
        indeg.resize(numCourses);
        //更新入度表和邻接表
        for (const auto& info: prerequisites) {
    
    
            edges[info[1]].push_back(info[0]);
            ++indeg[info[0]];
        }

        queue<int> q;
        //入度为0的先入队列
        for (int i = 0; i < numCourses; ++i) {
    
    
            if (indeg[i] == 0) {
    
    
                q.push(i);
            }
        }

        int visited = 0;
        while (!q.empty()) {
    
    
            ++visited;
            int u = q.front();
            q.pop();
            for (int v: edges[u]) {
    
    
                --indeg[v];
                if (indeg[v] == 0) {
    
    
                    q.push(v);
                }
            }
        }

        return visited == numCourses;
    }
};

búsqueda en profundidad

La búsqueda primero en profundidad es una especie de pensamiento inverso, y el último elemento de la ordenación topológica se coloca primero en la pila.
Para cualquier nodo en el gráfico, tiene tres estados durante el proceso de búsqueda, a saber:

  • "No buscado": No hemos buscado este nodo;
  • "Buscando": hemos buscado en este nodo, pero no hemos rastreado hasta este nodo, es decir, este nodo no se ha colocado en la pila y hay nodos adyacentes que no se han buscado);
  • "Completado": hemos buscado y rastreado este nodo, es decir, este nodo se ha insertado en la pila, y todos los nodos adyacentes de este nodo aparecen en la parte inferior de la pila, lo que cumple con los requisitos de clasificación topológica.

A través de los tres estados anteriores, podemos darle al algoritmo un flujo de clasificación topológica utilizando la búsqueda primero en profundidad. Al comienzo de cada ronda de búsqueda, seleccionamos aleatoriamente un nodo "no buscado" para comenzar la búsqueda primero en profundidad.

Marcamos el nodo u buscado actualmente como "buscando", y recorremos cada nodo adyacente v de este nodo:

  • Si v es "no buscado", entonces comenzamos a buscar v, y retrocedemos a u después de completar la búsqueda;
  • Si v está "buscando", entonces hemos encontrado un ciclo en el gráfico, por lo que no hay clasificación topológica;
  • Si v está "completado", significa que v ya está en la pila, pero u aún no está en la pila, por lo que no importa cuándo se coloque u en la pila, no afectará la relación topológica anterior (u, v) , y no hay necesidad de hacer ninguna operación.

Cuando todos los vecinos de u están "completados", colocamos u en la pila y lo marcamos como "completado". Una vez que finaliza todo el proceso de búsqueda en profundidad, si no encontramos el anillo en el gráfico, almacenamos todos los n nodos en la pila, y el orden desde la parte superior de la pila hasta la parte inferior de la pila es una ordenación topológica .

class Solution {
    
    
private:
    vector<vector<int>> edges;
    vector<int> visited;
    bool valid = true;

public:
    void dfs(int u) {
    
    
        visited[u] = 1;
        for (int v: edges[u]) {
    
    
            if (visited[v] == 0) {
    
    
                dfs(v);
                if (!valid) {
    
    
                    return;
                }
            }
            else if (visited[v] == 1) {
    
    
                valid = false;
                return;
            }
        }
        visited[u] = 2;
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
    
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto& info: prerequisites) {
    
    
            edges[info[1]].push_back(info[0]);
        }
        for (int i = 0; i < numCourses && valid; ++i) {
    
    
            if (!visited[i]) {
    
    
                dfs(i);
            }
        }
        return valid;
    }
};

Supongo que te gusta

Origin blog.csdn.net/weixin_45184581/article/details/129055772
Recomendado
Clasificación