Lexicographically Smallest Topological Ordering
Given a directed graph with N vertices and M edges that may contain cycles, the task is to find the lexicographically smallest topological ordering of the graph if it exists otherwise print -1 (if the graph has cycles).
Lexicographically smallest topological ordering means that if two vertices in a graph do not have any incoming edge then the vertex with the smaller number should appear first in the ordering.
For Example, in the image below many topological orderings are possible e.g 5 2 3 4 0 1, 5 0 2 4 3 1.
But the smallest ordering is 4 5 0 2 3 1.
Examples:
Input:
Output: 4 5 0 2 3 1
Even though 5 4 0 2 3 1 is also a valid topological
ordering of the given graph but it is not
lexicographically smallest.
Approach: We will use Kahn’s algorithm for Topological Sorting with a modification. Instead of using a queue we will use a multiset to store the vertices to make sure that every time we pick a vertex it is the smallest possible of all. The overall Time complexity changes to
Below is the implementation of the above approach:
CPP
#include<bits/stdc++.h>
using namespace std;
vector<vector< int >> adj;
void addEdge( int x, int y)
{
adj[x].push_back(y);
}
void topologicalSort()
{
int V = adj.size();
vector< int > in_degree(V, 0);
for ( int u = 0; u < V; u++) {
for ( auto x: adj[u])
in_degree[x]++;
}
multiset< int > s;
for ( int i = 0; i < V; i++)
if (in_degree[i] == 0)
s.insert(i);
int cnt = 0;
vector< int > top_order;
while (!s.empty()) {
int u = *s.begin();
s.erase(s.begin());
top_order.push_back(u);
for ( auto x:adj[u])
if (--in_degree[x] == 0)
s.insert(x);
cnt++;
}
if (cnt != V) {
cout << -1;
return ;
}
for ( int i = 0; i < top_order.size(); i++)
cout << top_order[i] << " " ;
}
int main()
{
int v = 6;
adj= vector<vector< int >>(v);
addEdge(5,2);
addEdge(5,0);
addEdge(4,0);
addEdge(4,1);
addEdge(2,3);
addEdge(3,1);
topologicalSort();
}
|
Java
import java.util.*;
class Main
{
static List<List<Integer>> adj;
static void addEdge( int x, int y)
{
adj.get(x).add(y);
}
static void topologicalSort()
{
int V = adj.size();
int [] in_degree = new int [V];
Arrays.fill(in_degree, 0 );
for ( int u = 0 ; u < V; u++) {
for ( int x: adj.get(u))
in_degree[x]++;
}
PriorityQueue<Integer> queue = new PriorityQueue<>();
for ( int i = 0 ; i < V; i++)
if (in_degree[i] == 0 )
queue.add(i);
int cnt = 0 ;
List<Integer> top_order = new ArrayList<>();
while (!queue.isEmpty()) {
int u = queue.poll();
top_order.add(u);
for ( int x: adj.get(u))
if (--in_degree[x] == 0 )
queue.add(x);
cnt++;
}
if (cnt != V) {
System.out.println(- 1 );
return ;
}
for ( int i = 0 ; i < top_order.size(); i++)
System.out.print(top_order.get(i) + " " );
}
public static void main (String[] args)
{
int v = 6 ;
adj = new ArrayList<>(v);
for ( int i = 0 ; i < v; i++) {
adj.add( new ArrayList<>());
}
addEdge( 5 , 2 );
addEdge( 5 , 0 );
addEdge( 4 , 0 );
addEdge( 4 , 1 );
addEdge( 2 , 3 );
addEdge( 3 , 1 );
topologicalSort();
}
}
|
Python3
import heapq as hq
def addEdge(x, y):
adj[x].append(y)
def topologicalSort():
V = len (adj)
in_degree = [ 0 ] * V
for u in range (V):
for x in adj[u]:
in_degree[x] + = 1
s = []
for i in range (V):
if in_degree[i] = = 0 :
hq.heappush(s, i)
cnt = 0
top_order = []
while s:
u = hq.heappop(s)
top_order.append(u)
for x in adj[u]:
in_degree[x] - = 1
if in_degree[x] = = 0 :
hq.heappush(s, x)
cnt + = 1
if cnt ! = V:
print ( - 1 )
return
for i in range ( len (top_order)):
print (top_order[i], end = " " )
if __name__ = = "__main__" :
v = 6
adj = [[] for _ in range (v)]
addEdge( 5 , 2 )
addEdge( 5 , 0 )
addEdge( 4 , 0 )
addEdge( 4 , 1 )
addEdge( 2 , 3 )
addEdge( 3 , 1 )
topologicalSort()
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
class MainClass
{
static List<List< int >> adj;
static void AddEdge( int x, int y)
{
adj[x].Add(y);
}
static void TopologicalSort()
{
int V = adj.Count;
int [] in_degree = new int [V];
for ( int i = 0; i < V; i++)
{
in_degree[i] = 0;
}
for ( int u = 0; u < V; u++)
{
foreach ( int x in adj[u])
{
in_degree[x]++;
}
}
Queue< int > queue = new Queue< int >();
for ( int i = 0; i < V; i++)
{
if (in_degree[i] == 0)
{
queue.Enqueue(i);
}
}
int cnt = 0;
List< int > top_order = new List< int >();
while (queue.Count != 0)
{
int u = queue.Dequeue();
top_order.Add(u);
foreach ( int x in adj[u])
{
if (--in_degree[x] == 0)
{
queue.Enqueue(x);
}
}
cnt++;
}
if (cnt != V)
{
Console.WriteLine(-1);
return ;
}
foreach ( int i in top_order)
{
Console.Write(i + " " );
}
}
public static void Main()
{
int v = 6;
adj = new List<List< int >>(v);
for ( int i = 0; i < v; i++)
{
adj.Add( new List< int >());
}
AddEdge(5, 2);
AddEdge(5, 0);
AddEdge(4, 0);
AddEdge(4, 1);
AddEdge(2, 3);
AddEdge(3, 1);
TopologicalSort();
}
}
|
Javascript
let adj = [];
function addEdge(x, y) {
adj[x].push(y);
}
function topologicalSort() {
let V = adj.length;
let in_degree = Array(V).fill(0);
for (let u = 0; u < V; u++) {
for (let i = 0; i < adj[u].length; i++)
in_degree[adj[u][i]]++;
}
let s = new Set();
for (let i = 0; i < V; i++)
if (in_degree[i] == 0)
s.add(i);
let cnt = 0;
let top_order = [];
while (s.size > 0) {
let u = s.values().next().value;
s. delete (u);
top_order.push(u);
for (let i = 0; i < adj[u].length; i++) {
if (--in_degree[adj[u][i]] == 0)
s.add(adj[u][i]);
}
cnt++;
}
if (cnt != V) {
console.log(-1);
return ;
}
console.log(top_order);
}
function main() {
let v = 6;
for (let i = 0; i < v; i++)
adj.push([]);
addEdge(5, 2);
addEdge(5, 0);
addEdge(4, 0);
addEdge(4, 1);
addEdge(2, 3);
addEdge(3, 1);
topologicalSort();
}
main();
|
Time Complexity: O(N)
Auxiliary Space: O(N)
Last Updated :
28 Mar, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...