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:
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> |
2
Time Complexity : O(N*LogN)