📜  将排列转换为身份排列所需的最小给定操作数

📅  最后修改于: 2021-10-27 16:52:13             🧑  作者: Mango

给定前n 个自然数的排列P (P1, P2, P3, … Pn)。找到将其转换为恒等排列的最少操作次数,即1, 2, 3, …, n其中每个操作定义为:
P[i] = P[P[P[i]]] \forall  i 从 1 到 n(基于 1 的索引)。如果无法转换,则打印-1
例子:

方法:首先,找出给定排列中的所有循环。这里,循环是一个有向图,其中从元素 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)