Minimum number of given operations required to convert a permutation into an identity permutation

26 May, 2021
Given a permutation P (P1, P2, P3, ... Pn) of first n natural numbers. Find the minimum number of operations to convert it into an identity permutation i.e. 1, 2, 3, ..., n where each operation is defined as: P[i] = P[P[P[i]]] i from 1 to n (1 based indexing). If there is no way to convert then print -1.Examples:  
Input: arr[] = {2, 3, 1} Output: 1 After 1 operation: P[1] = P[P[P[1]]] = P[P[2]] = P[3] = 1 P[2] = P[P[P[2]]] = P[P[3]] = P[1] = 2 P[3] = P[P[P[3]]] = P[P[1]] = P[2] = 3 Thus after 1 operation we obtain an identity permutation.Input: arr[] = {2, 1, 3} Output: -1 There is no way to obtain identity permutation no matter how many operations we apply.  
 
Approach: First, find all the cycles in the given permutation. Here, a cycle is a directed graph in which there is an edge from an element e to the element on position e. For example, Here’s the graph for permutation {4, 6, 5, 3, 2, 1, 8, 7}  
Now in one operation, each cycle of length 3k breaks into 3 cycles each of length k while cycles of length 3k+1 or 3k+2 do not break. Since in the end, we need all cycles of length 1, therefore, all cycles must be a power of 3 otherwise answer doesn’t exist. The answer would then be the maximum of log(base 3) of all cycle lengths.Below is the implementation of the above approach: 
C++
Java
Python3
C#
PHP
Javascript
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std; int calculateCycleOperations(int len){    int cycle_operations = 0;    while (len) {        len /= 3;        ++cycle_operations;    }    return --cycle_operations;} // Function to return the minimum operations requiredint minimumOperations(int p[], int n){     // Array to keep track of visited elements    bool visited[n + 1] = { 0 };     // To store the final answer    int ans = 0;     // Looping through all the elements    for (int i = 1; i <= n; i++) {         // Current element        int ele = p[i];         // If current element is not present in the        // previous cycles then only consider this        if (!visited[ele]) {             // Mark current element visited so that it            // will not be considered in other cycles            visited[ele] = 1;             // To store the length of each cycle            int len = 1;            ele = p[ele];             // Calculating cycle length            while (!visited[ele]) {                visited[ele] = 1;                ++len;                ele = p[ele];            }             // Operations needed for this cycle to reduce            // to length 1 (if possible)            int operations = calculateCycleOperations(len);             // Checking cycle length to be power of 3            // if not, then return -1            int num = pow(3, operations);            if (num != len) {                return -1;            }             // Taking maximum of the operations            ans = max(ans, operations);        }    }    return ans;} // Driver codeint main(){    // 1-based indexing    int P[] = { -1, 4, 6, 5, 3, 2, 7, 8, 9, 1 };    int n = (sizeof(P) / sizeof(P[0])) - 1;     // Calling function    cout << minimumOperations(P, n);     return 0;}
// Java implementation of the approachimport java.util.*; class GFG{ static int calculateCycleOperations(int len){    int cycle_operations = 0;    while (len > 0)    {        len /= 3;        ++cycle_operations;    }    return --cycle_operations;} // Function to return the minimum operations requiredstatic int minimumOperations(int p[], int n){     // Array to keep track of visited elements    int []visited = new int[n+1];    Arrays.fill(visited,0);     // To store the final answer    int ans = 0;     // Looping through all the elements    for (int i = 1; i <= n; i++)    {         // Current element        int ele = p[i];         // If current element is not present in the        // previous cycles then only consider this        if (visited[ele] == 0)        {             // Mark current element visited so that it            // will not be considered in other cycles            visited[ele] = 1;             // To store the length of each cycle            int len = 1;            ele = p[ele];             // Calculating cycle length            while (visited[ele] == 0)            {                visited[ele] = 1;                ++len;                ele = p[ele];            }             // Operations needed for this cycle to reduce            // to length 1 (if possible)            int operations = calculateCycleOperations(len);             // Checking cycle length to be power of 3            // if not, then return -1            int num = (int)Math.pow(3, operations);            if (num != len) {                return -1;            }             // Taking maximum of the operations            ans = Math.max(ans, operations);        }    }    return ans;} // Driver codepublic static void main(String args[]){    // 1-based indexing    int P[] = { -1, 4, 6, 5, 3, 2, 7, 8, 9, 1 };    int n = P.length-1;     // Calling function    System.out.println(minimumOperations(P, n));}} // This code is contributed by// Surendra_Gangwar
# Python3 implementation of the approachdef calculateCycleOperations(length):     cycle_operations = 0    while length > 0:        length //= 3        cycle_operations += 1         return cycle_operations - 1 # Function to return the minimum# operations requireddef minimumOperations(p, n):     # Array to keep track of visited elements    visited = [0] * (n + 1)     # To store the final answer    ans = 0     # Looping through all the elements    for i in range(1, n + 1):         # Current element        ele = p[i]         # If current element is not present in the        # previous cycles then only consider this        if not visited[ele]:             # Mark current element visited so that it            # will not be considered in other cycles            visited[ele] = 1             # To store the length of each cycle            length = 1            ele = p[ele]             # Calculating cycle length            while not visited[ele]:                visited[ele] = 1                length += 1                ele = p[ele]                         # Operations needed for this cycle to            # reduce to length 1 (if possible)            operations = calculateCycleOperations(length)             # Checking cycle length to be power            # of 3 if not, then return -1            num = pow(3, operations)            if num != length:                return -1             # Taking maximum of the operations            ans = max(ans, operations)             return ans # Driver codeif __name__ == "__main__":     # 1-based indexing    P = [-1, 4, 6, 5, 3, 2, 7, 8, 9, 1]    n = len(P) - 1     # Calling function    print(minimumOperations(P, n)) # This code is contributed by Rituraj Jain
// C# implementation of the above approachusing System; class GFG{     static int calculateCycleOperations(int len)    {        int cycle_operations = 0;        while (len > 0)        {            len /= 3;            ++cycle_operations;        }        return --cycle_operations;    }         // Function to return the minimum operations required    static int minimumOperations(int []p, int n)    {             // Array to keep track of visited elements        int []visited = new int[n+1];         // To store the final answer        int ans = 0;             // Looping through all the elements        for (int i = 1; i <= n; i++)        {                 // Current element            int ele = p[i];                 // If current element is not present in the            // previous cycles then only consider this            if (visited[ele] == 0)            {                     // Mark current element visited so that it                // will not be considered in other cycles                visited[ele] = 1;                     // To store the length of each cycle                int len = 1;                ele = p[ele];                     // Calculating cycle length                while (visited[ele] == 0)                {                    visited[ele] = 1;                    ++len;                    ele = p[ele];                }                     // Operations needed for this cycle to reduce                // to length 1 (if possible)                int operations = calculateCycleOperations(len);                     // Checking cycle length to be power of 3                // if not, then return -1                int num = (int)Math.Pow(3, operations);                if (num != len)                {                    return -1;                }                     // Taking maximum of the operations                ans = Math.Max(ans, operations);            }        }        return ans;    }         // Driver code    public static void Main()    {        // 1-based indexing        int []P = { -1, 4, 6, 5, 3, 2, 7, 8, 9, 1 };        int n = P.Length-1;             // Calling function        Console.WriteLine(minimumOperations(P, n));    }} // This code is contributed by Ryuga
<?php// PHP implementation of the approachfunction calculateCycleOperations($len){    $cycle_operations = 0;    while ($len)    {        $len = (int)($len / 3);        ++$cycle_operations;    }    return --$cycle_operations;} // Function to return the minimum// operations requiredfunction minimumOperations($p, $n){     // Array to keep track of visited elements    $visited[$n + 1] = array(0);     // To store the final answer    $ans = 0;     // Looping through all the elements    for ($i = 1; $i <= $n; $i++)    {         // Current element        $ele = $p[$i];         // If current element is not present in the        // previous cycles then only consider this        if (!$visited[$ele])        {             // Mark current element visited so that it            // will not be considered in other cycles            $visited[$ele] = 1;             // To store the length of each cycle            $len = 1;            $ele = $p[$ele];             // Calculating cycle length            while (!$visited[$ele])            {                $visited[$ele] = 1;                ++$len;                $ele = $p[$ele];            }             // Operations needed for this cycle to reduce            // to length 1 (if possible)            $operations = calculateCycleOperations($len);             // Checking cycle length to be power of 3            // if not, then return -1            $num = pow(3, $operations);            if ($num != $len)            {                return -1;            }             // Taking maximum of the operations            $ans = max($ans, $operations);        }    }    return $ans;} // Driver code // 1-based indexing$P = array(-1, 4, 6, 5, 3, 2, 7, 8, 9, 1);$n = sizeof($P) - 1; // Calling functionecho minimumOperations($P, $n); // This code is contributed by Akanksha Rai?>
<script> // JavaScript implementation of the approach function calculateCycleOperations(len){    let cycle_operations = 0;    while (len > 0)    {        len = Math.floor(len / 3);        ++cycle_operations;    }    return --cycle_operations;}   // Function to return the minimum operations requiredfunction minimumOperations(p, n){       // Array to keep track of visited elements    let visited = Array.from({length: n + 1}, (_, i) => 0);       // To store the final answer    let ans = 0;       // Looping through all the elements    for (let i = 1; i <= n; i++)    {           // Current element        let ele = p[i];           // If current element is not present in the        // previous cycles then only consider this        if (visited[ele] == 0)        {               // Mark current element visited so that it            // will not be considered in other cycles            visited[ele] = 1;               // To store the length of each cycle            let len = 1;            ele = p[ele];               // Calculating cycle length            while (visited[ele] == 0)            {                visited[ele] = 1;                ++len;                ele = p[ele];            }               // Operations needed for this cycle to reduce            // to length 1 (if possible)            let operations = calculateCycleOperations(len);               // Checking cycle length to be power of 3            // if not, then return -1            let num = Math.floor(Math.pow(3, operations));            if (num != len) {                return -1;            }               // Taking maximum of the operations            ans = Math.max(ans, operations);        }    }    return ans;}         // Driver code         // 1-based indexing    let P = [ -1, 4, 6, 5, 3, 2, 7, 8, 9, 1 ];    let n = P.length - 1;       // Calling function    document.write(minimumOperations(P, n));                 </script>
2
 
Time Complexity : O(N*LogN)  
rituraj_jain
SURENDRA_GANGWAR
ankthon
Akanksha_Rai
souravghosh0416
permutation
Arrays
Competitive Programming
Graph
Hash
Arrays
Hash
permutation
Graph
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Maximum and minimum of an array using minimum number of comparisons
Top 50 Array Coding Problems for Interviews
Multidimensional Arrays in Java
Stack Data Structure (Introduction and Program)
Linear Search
Competitive Programming - A Complete Guide
Practice for cracking any coding interview
Modulo 10^9+7 (1000000007)
Arrow operator -> in C/C++ with Examples
Fast I/O for Competitive Programming