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]]]
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.
Algorithm:
Step 1: Create the calculateCycleOperations function, which accepts an integer as an input named “len”.
Step 2: Initialize the cycle operations variable with a value of 0 within the function. Step 3: Start a while loop with the condition “len” is positive.
a. divided “len” by three and update it every time
b. divided “len” by three and update it every time Step 4: Return the cycle operations value that has been reduced by 1.
Step 5: Create the function minimumOperations, which has two inputs: an integer array p[] and an integer n.
Step 6: Set all values in a boolean array with the name visited and a size of n+1 to 0.
Step 7: create the variable “ans” with the value 0.
Step 8: start a for loop and traverse through each element of the array.
a. If the current element is not present in previous cycles, then only consider it.
b. Mark the current element as visited so that it will not be considered in other cycles.
c. Initialize a variable named ele as the current element, and a variable named len as 1.
d. Start a while loop with the condition element is not visited
1. Update the value of ele with p[ele], and increment len by 1
e. Calculate the number of operations needed for this cycle to reduce to length 1 (if possible) by calling the function calculateCycleOperations.
f. Check if the length of the cycle is a power of 3, if not, then return -1.
g. Take the maximum of the operations and ans.
Step 8: Return ans
Below is the implementation of the above approach:
// 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 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 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# 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 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 ?> |
<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)
Auxiliary Space: O(N)