Skip to content
Related Articles

Related Articles

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

View Discussion
Improve Article
Save Article
Like Article
  • Difficulty Level : Hard
  • Last Updated : 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]]] \forall  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:
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++




// 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 required
int 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 code
int 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




// Java implementation of the approach
import 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 required
static 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 code
public 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




# Python3 implementation of the approach
def calculateCycleOperations(length):
 
    cycle_operations = 0
    while length > 0:
        length //= 3
        cycle_operations += 1
     
    return cycle_operations - 1
 
# Function to return the minimum
# operations required
def 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 code
if __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#




// C# implementation of the above approach
using 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
// PHP implementation of the approach
function calculateCycleOperations($len)
{
    $cycle_operations = 0;
    while ($len)
    {
        $len = (int)($len / 3);
        ++$cycle_operations;
    }
    return --$cycle_operations;
}
 
// Function to return the minimum
// operations required
function 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 function
echo minimumOperations($P, $n);
 
// This code is contributed by Akanksha Rai
?>


Javascript




<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 required
function 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>


Output: 

2

 

Time Complexity : O(N*LogN) 
 


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!