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

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:

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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;
}
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

# 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
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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
chevron_right

filter_none

edit
close

play_arrow

link
brightness_4
code

<?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
?>
chevron_right

Output:
2

Time Complexity : O(N*LogN)




Recommended Posts:


Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Article Tags :