📜  字典序最小的拓扑排序

📅  最后修改于: 2021-10-25 03:28:56             🧑  作者: Mango

给定一个有N个顶点和M 条边的有向图,其中可能包含环,任务是找到该图的字典序最小拓扑排序,如果它存在,否则打印-1 (如果图有环)。
字典序最小的拓扑排序意味着如果图中的两个顶点没有任何传入边,那么编号较小的顶点应首先出现在排序中。
例如,在下图中,许多拓扑排序是可能的,例如5 2 3 4 0 1, 5 0 2 4 3 1
但最小的顺序是4 5 0 2 3 1
例子:

方法:我们将使用 Kahn 的拓扑排序算法进行修改。我们将使用多重集来存储顶点,而不是使用队列,以确保每次我们选择一个顶点时,它都是可能的最小顶点。整体时间复杂度变为O(VlogV+E)
下面是上述方法的实现:

CPP
// C++ implementation of the approach
#include 
using namespace std;
 
// Class to represent a graph
class Graph {
    int V; // No. of vertices'
 
    // Pointer to an array containing
    // adjacency listsList
    list* adj;
 
public:
    Graph(int V); // Constructor
 
    // Function to add an edge to graph
    void addEdge(int u, int v);
 
    // Function to print the required topological
    // sort of the given graph
    void topologicalSort();
};
 
// Constructor
Graph::Graph(int V)
{
    this->V = V;
    adj = new list[V];
}
 
// Function to add an edge to the graph
void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v);
}
 
// Function to print the required topological
// sort of the given graph
void Graph::topologicalSort()
{
    // Create a vector to store indegrees of all
    // the vertices
    // Initialize all indegrees to 0
    vector in_degree(V, 0);
 
    // Traverse adjacency lists to fill indegrees of
    // vertices
    // This step takes O(V+E) time
    for (int u = 0; u < V; u++) {
        list::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)
            in_degree[*itr]++;
    }
 
    // Create a set and inserting all vertices with
    // indegree 0
    multiset s;
    for (int i = 0; i < V; i++)
        if (in_degree[i] == 0)
            s.insert(i);
 
    // Initialize count of visited vertices
    int cnt = 0;
 
    // Create a vector to store result (A topological
    // ordering of the vertices)
    vector top_order;
 
    // One by one erase vertices from setand insert
    // adjacents if indegree of adjacent becomes 0
    while (!s.empty()) {
 
        // Extract vertex with minimum number from multiset
        // and add it to topological order
        int u = *s.begin();
        s.erase(s.begin());
        top_order.push_back(u);
 
        // Iterate through all its neighbouring nodes
        // of erased node u and decrease their in-degree
        // by 1
        list::iterator itr;
        for (itr = adj[u].begin(); itr != adj[u].end(); itr++)
 
            // If in-degree becomes zero, add it to queue
            if (--in_degree[*itr] == 0)
                s.insert(*itr);
 
        cnt++;
    }
 
    // Check if there was a cycle
    if (cnt != V) {
        cout << -1;
        return;
    }
 
    // Print topological order
    for (int i = 0; i < top_order.size(); i++)
        cout << top_order[i] << " ";
}
 
// Driver code
int main()
{
    // Create the graph
    Graph g(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);
 
    // Find the required topological order
    g.topologicalSort();
 
    return 0;
}


输出:
4 5 0 2 3 1

时间复杂度: O(N)
辅助空间: O(N)