给定前n 个自然数的排列P (P1, P2, P3, … Pn)。找到将其转换为恒等排列的最少操作次数,即1, 2, 3, …, n其中每个操作定义为:
P[i] = P[P[P[i]]] i 从 1 到 n(基于 1 的索引)。如果无法转换,则打印-1 。
例子:
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.
方法:首先,找出给定排列中的所有循环。这里,循环是一个有向图,其中从元素 e 到位置 e 上的元素有一条边。
例如,这是排列 {4, 6, 5, 3, 2, 1, 8, 7} 的图
现在在一次操作中,每个长度为 3k 的循环分解为 3 个长度为 k 的循环,而长度为 3k+1 或 3k+2 的循环不会中断。由于最后,我们需要所有长度为 1 的循环,因此,所有循环都必须是 3 的幂,否则答案不存在。答案将是所有周期长度的 log(base 3) 的最大值。
下面是上述方法的实现:
C++
// C++ implementation of the approach
#include
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
Javascript
2
时间复杂度:O(N*LogN)