Open In App

Generate lexicographically smallest Permutation of 1 to N where elements follow given relation

Last Updated : 22 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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


Output

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)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads