📜  按字典顺序最小的拓扑顺序

📅  最后修改于: 2021-05-06 19:46:38             🧑  作者: 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)

下面是上述方法的实现:

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