Generate lexicographically smallest Permutation of 1 to N where elements follow given relation
Given an integer N and an array arr[] of M pairs of type (Ai, Bi), the task is to generate the lexicographically smallest possible permutation of 1 to N such that every Ai, occurs before every Bi.
Examples:
Input: N = 4, arr[] = { {2, 1}, {3, 4}, {2, 4} }
Output: 2 1 3 4
Explanation: The following five permutations P satisfy the condition:
(2, 1, 3, 4), (2, 3, 1, 4), (2, 3, 4, 1), (3, 2, 1, 4), (3, 2, 4, 1).
The lexicographically smallest among them is (2, 1, 3, 4).Input: N = 2, arr[] = { {2, 1} }
Output: 2 1
Approach: The problem can be solved using the concept of Graph based on the following idea:
Consider a N vertex graph where there is an directed edge from A to B if A occurs before B in the permutation.
- So the target is to find a ordering such that any vertex occurs in the permutation after all its predecessors (the vertices which have edges directed to this one) have occurred in the permutation.
- While doing so, move from the least value to the maximum possible value for getting the lexicographically smallest permutation.
This can be done with the help of topological sorting.
- The topological sort will start from the vertices having indegree 0 and in sequence of smaller to greater value.
- After the topological sorting is over, if any vertex is still not included in the permutation, then no such permutation is possible.
Follow the below steps to solve the problem:
- Initialize one vector (say ans) to store the resulting permutation.
- Visit the M pairs and create directed edges from the first value of arr[i] to the second value of arr[i]. Also, increase the indegree of the second value of arr[i] by 1.
- Now find all the elements with indegree 0, push them in the resultant permutation in increasing order and start the topological sort.
- Add any vertex to the permutation when its indegree becomes 0.
- Maintain the lexicographic ordering while doing so, i.e. move from the lower value to the higher value.
- Take the help of min heap to perform the topological sorting:
- Initially keep the vertices with indegree 0 in the heap.
- Then pop the least value vertex, append it to the ans, remove all its edges and decrease the indegree by 1 of all the vertices connected to it.
- If the indegree of any vertex becomes 0 in this process, push that into the heap.
- Return ans as the final required permutation.
Below is the implementation of the above approach.
C++
// C++ program to implement above approach #include <bits/stdc++.h> using namespace std; // Function to obtain the permutation vector< int > Calculate( int n, int m, vector<pair< int , int > > arr) { // Prepare an empty array ans vector< int > ans; vector< int > indegree(n); vector<vector< int > > out(n); // Build the directed graph for ( int i = 0; i < m; i++) { int a = arr[i].first; int b = arr[i].second; a--; b--; // Calculate indegree of every element indegree[b] = indegree[b] + 1; // Store connection of each node out[a].push_back(b); } // Declaring the min heap priority_queue< int , vector< int >, greater< int > > heap; for ( int i = 0; i < n; ++i) { if (indegree[i] == 0) { // Push elements in priority queue // if indegree is 0 heap.push(i); } } // Run topological sort while (!heap.empty()) { // Choose vertex with degree 0, // denoted by i int i = heap.top(); heap.pop(); // Push i+1 to the tail of ans ans.push_back(i + 1); // Remove i and edges going out from i for ( int j : out[i]) { indegree[j] -= 1; // In the process if any node's indegree // becomes 0 then push the element // to the priority queue if (indegree[j] == 0) { heap.push(j); } } } // If size of ans is not n then // output would is not possible if (ans.size() != n) { ans.clear(); ans.push_back(-1); } return ans; } // Driver code int main() { int N = 4, M = 3; vector<pair< int , int > > arr = { { 2, 1 }, { 3, 4 }, { 2, 4 } }; // Function call vector< int > res = Calculate(N, M, arr); for ( int x : res) cout << x << " " ; return 0; } |
Java
// Java program to implement above approach import java.io.*; import java.util.*; class GFG { // Function to obtain the permutation public static ArrayList<Integer> Calculate( int n, int m, int arr[][]) { // Prepare an empty array ans ArrayList<Integer> ans = new ArrayList<Integer>(); int indegree[] = new int [n]; ArrayList<ArrayList<Integer> > out = new ArrayList<ArrayList<Integer> >(n); for ( int i = 0 ; i < n; i++) { out.add( new ArrayList<Integer>()); } // Build the directed graph for ( int i = 0 ; i < m; i++) { int a = arr[i][ 0 ]; int b = arr[i][ 1 ]; a--; b--; // Calculate indegree of every element indegree[b] = indegree[b] + 1 ; // Store connection of each node out.get(a).add(b); } // Declaring the min heap PriorityQueue<Integer> heap = new PriorityQueue<>(); for ( int i = 0 ; i < n; ++i) { if (indegree[i] == 0 ) { // Push elements in priority queue // if indegree is 0 heap.add(i); } } // Run topological sort while (!heap.isEmpty()) { // Choose vertex with degree 0, // denoted by i int i = heap.peek(); heap.poll(); // Push i+1 to the tail of ans ans.add(i + 1 ); // Remove i and edges going out from i for (Integer j : out.get(i)) { indegree[j] -= 1 ; // In the process if any node's indegree // becomes 0 then push the element // to the priority queue if (indegree[j] == 0 ) { heap.add(j); } } } // If size of ans is not n then // output would is not possible if (ans.size() != n) { ans.clear(); ans.add(- 1 ); } return ans; } // Driver Code public static void main(String[] args) { int N = 4 , M = 3 ; int arr[][] = { { 2 , 1 }, { 3 , 4 }, { 2 , 4 } }; // Function call ArrayList<Integer> res = Calculate(N, M, arr); for (Integer x : res) System.out.print(x + " " ); } } // This code is contributed by Rohit Pradhan |
Python3
# Python program to implement above approach def Calculate(n, m, arr): # Prepare an empty array ans ans = [] indegree = [ 0 ] * n out = [[] for i in range (n)] # Build the directed graph for i in range (m): a = arr[i][ 0 ] b = arr[i][ 1 ] a - = 1 b - = 1 # Calculate indegree of every element indegree[b] + = 1 # Store connection of each node out[a].append(b) # Declaring the min heap heap = [] for i in range (n): if indegree[i] = = 0 : # Push elements in priority queue # if indegree is 0 heap.append(i) # Run topological sort while heap: # Choose vertex with degree 0, # denoted by i i = heap.pop( 0 ) # Push i+1 to the tail of ans ans.append(i + 1 ) # Remove i and edges going out from i for j in out[i]: indegree[j] - = 1 # In the process if any node's indegree # becomes 0 then push the element # to the priority queue if indegree[j] = = 0 : heap.append(j) # If size of ans is not n then # output would is not possible if len (ans) ! = n: ans = [ - 1 ] return ans # Driver code if __name__ = = '__main__' : n = 4 m = 3 arr = [[ 2 , 1 ], [ 3 , 4 ], [ 2 , 4 ]] res = Calculate(n, m, arr) print (res) # This code is contributed by abhinavprkash. |
C#
// C# program to implement above approach using System; using System.Collections.Generic; class GFG { static List< int > Calculate( int n, int m, int [, ] arr) { // Prepare an empty array ans List< int > ans = new List< int >(); int [] indegree = new int [n]; // for (int i = 0; i < n; i++) // indegree[i] = 0; List<List< int > > Out = new List<List< int > >(); for ( var i = 0; i < n; i++) Out.Add( new List< int >()); // Build the directed graph for ( var i = 0; i < m; i++) { var a = arr[i, 0]; var b = arr[i, 1]; a -= 1; b -= 1; // Calculate indegree of every element indegree[b] += 1; // Store connection of each node Out[a].Add(b); } // Declaring the min heap List< int > heap = new List< int >(); for ( var i = 0; i < n; i++) { if (indegree[i] == 0) { // Push elements in priority queue // if indegree is 0 heap.Add(i); } } // Run topological sort while (heap.Count > 0) { heap.Sort(); // Choose vertex with degree 0, // denoted by i var i = heap[0]; heap.RemoveAt(0); // Push i+1 to the tail of ans ans.Add(i + 1); // Remove i and edges going out from i for ( var k = 0; k < Out[i].Count; k++) { var j = Out[i][k]; indegree[j] -= 1; // In the process if any node's indegree // becomes 0 then push the element // to the priority queue if (indegree[j] == 0) heap.Add(j); } } // If size of ans is not n then // output would is not possible if (ans.Count != n) { ans.Clear(); ans.Add(-1); } return ans; } // Driver code public static void Main( string [] args) { var n = 4; var m = 3; int [, ] arr = { { 2, 1 }, { 3, 4 }, { 2, 4 } }; var res = Calculate(n, m, arr); foreach ( var i in res) Console.Write(i + " " ); } } // This code is contributed by phasing17 |
Javascript
//JavaScript program to implement above approach function Calculate(n, m, arr) { // Prepare an empty array ans var ans = []; var indegree = new Array(n).fill(0); var out = []; for ( var i = 0; i < n; i++) out.push([ ]); // Build the directed graph for ( var i = 0; i < m; i++) { var a = arr[i][0]; var b = arr[i][1]; a -= 1; b -= 1; // Calculate indegree of every element indegree[b] += 1; // Store connection of each node out[a].push(b); } // Declaring the min heap var heap = []; for ( var i = 0; i < n; i++) { if (indegree[i] == 0) { // Push elements in priority queue // if indegree is 0 heap.push(i); } } // Run topological sort while (heap.length > 0) { // Choose vertex with degree 0, // denoted by i var i = heap.shift(); // Push i+1 to the tail of ans ans.push(i + 1); // Remove i and edges going out from i for ( var k = 0; k < out[i].length; k++) { var j = out[i][k]; indegree[j] -= 1; // In the process if any node's indegree // becomes 0 then push the element // to the priority queue if (indegree[j] == 0) heap.push(j); } } // If size of ans is not n then // output would is not possible if (ans.length != n) ans = [-1]; return ans; } // Driver code var n = 4; var m = 3; var arr = [[2, 1], [3, 4], [2, 4]]; var res = Calculate(n, m, arr); console.log(res); // This code is contributed by phasing17 |
2 1 3 4
Time Complexity: O(N+M*log(M)) where N is the number of vertices and M is the number of edges in the directed graph.
Auxiliary Space: O(N+M)
Please Login to comment...