📜  以指定动作返回 {1, 2, ..n} 的步骤

📅  最后修改于: 2022-05-13 01:57:50.422000             🧑  作者: Mango

以指定动作返回 {1, 2, ..n} 的步骤

给定一个包含前 n 个自然数排列的数组 move[],该数组的每个元素表示一个移动,每个元素显示一个索引,该索引在每个步骤之后该元素去。现在按照这些步骤,我们需要告诉数组 [1..n] 返回到 [1..N] 的步骤数。一个步骤定义如下,在一个步骤之后,每个元素将被移动到由移动数组索引定义的位置。
例子 :

Input  : moves[] = [4, 5, 1, 3, 2]
Output : 6
Explanation:
We need to consider an array of first 5 
natural numbers, i.e., arr[] = {1, 2, 3, 4, 5} as
size of moves[] is 5.
Now we one by one move elements of arr[] using 
given moves.
      moves[] = [4, 5, 1, 3, 2]
    arr[] = [1, 2, 3, 4, 5] 
In step 1, we move 1 to position 4, 2 to position
5, 3 to position 1, 4 to position 3 and 5 to 
position 2.
After step 1: arr[] = [3, 5, 4, 1, 2]
In step 2, we move 3 to position 4, 5 to position
5, 4 to position 1, 1 to position 3 and 2 to 
position 2
After step 2: arr[] = [4, 2, 1, 3, 5]
After step 3: arr[] = [1, 5, 3, 4, 2]
After step 4: arr[] = [3, 2, 4, 1, 5]
After step 5: arr[] = [4, 5, 1, 3, 2]
After step 6: arr[] = [1, 2, 3, 4, 5]
So we can reach to initial array in 6 steps, 
this is the minimum steps for reverting to 
the initial configuration of array.

Input  : moves[] = {3, 2, 1}
Output : 2

我们可以通过观察形成的序列之间的模式来解决这个问题。移动数组的一组特定元素形成一个循环。如上移动数组示例 [4, 1, 3] 和 [5, 2] 就是两个这样的集合。这两个周期是独立的。

[4, 1, 3] causes [1, 3, 4] -> [3, 4, 1] -> [4, 1, 3] 
-> [1, 3, 4] -> [3, 4, 1] -> [4, 1, 3] -> [1, 3, 4]

[5, 2] causes [2, 5] -> [5, 2] -> [2, 5] -> [5, 2]
 -> [2, 5] -> [5, 2] -> [2, 5]

从上面的变化我们可以看出,长度为 3 的循环需要 3 步才能到达相同的状态,而长度为 2 的循环需要 2 步才能到达相同的状态。一般来说,如果一个循环的长度为 N,那么在 N 步之后,我们可以达到相同的状态。
现在,如果给定的移动数组只有一个循环,那么我们可以在移动数等于数组中的总元素时达到起始状态,但如果它有超过 1 个循环,那么它们都独立移动它们的元素,它们都将达到x 次移动后的起始状态,其中 x 应该被所有循环长度整除,因为除以所有循环长度的最小 x 是它们的 LCM,我们仍然要找到所有循环长度的 LCM。
可以通过逐个访问元素来找到循环长度,从我们将移动的任何元素开始直到到达起始元素,我们将计算此过程中的元素数量,这将是相应的循环长度。

Below is example of cycles found for some moves arrays,
[2, 3, 1, 5, 4]     ->  [2, 3, 1] and [5, 4]
[1, 2, 3, 4, 5] ->  [1] [2] [3] [4] [5]
[2, 3, 4, 1, 5] ->  [2, 3, 4, 1] and [5]

剩下的就是计算这些长度的 LCM,这些长度可以使用 GCD 轻松计算。

C++
// C++ program to get minimum steps to return to
// initial array with specified movement
#include 
using namespace std;
 
// Utility method to get lcm of a and b
int lcm(int a, int b)
{
    return (a * b) / __gcd(a, b);
}
 
// Method returns minimum number of steps to
// return to initial array
int getMinStepsToSort(int moves[], int N)
{
    // initially all cells are unvisited
    bool visit[N];
    memset(visit, false, sizeof(visit));
 
    // looping over all elements to get
    // various cycle
    int steps = 1;
    for (int i = 0; i < N; i++) {
        // if already visited, that means it
        // was a part of some cycle
        if (visit[i])
            continue;
 
        int cycleLen = 0;
 
        // Looping among cycle elements,  -1 is
        // for converting value to 0-index based
        for (int j = i; !visit[j]; j = moves[j] - 1) {
            cycleLen++;
            visit[j] = true;
        }
 
        // Take the lcm of current result and
        // new cycle length
        steps = lcm(steps, cycleLen);
    }
    return steps;
}
 
// Driver code to test above methods
int main()
{
    int moves[] = { 4, 5, 1, 3, 2 };
    int N = sizeof(moves) / sizeof(int);
 
    cout << getMinStepsToSort(moves, N);
 
    return 0;
}


Java
// Java program to get minimum steps to
// return to initial array with specified
// movement
import java.util.Arrays;
 
class GFG {
 
    // Recursive function to return gcd
    // of a and b
    static int __gcd(int a, int b)
    {
        // Everything divides 0
        if (a == 0 || b == 0)
            return 0;
 
        // base case
        if (a == b)
            return a;
 
        // a is greater
        if (a > b)
            return __gcd(a - b, b);
 
        return __gcd(a, b - a);
    }
 
    // Utility method to get lcm of a and b
    static int lcm(int a, int b)
    {
        return (a * b) / __gcd(a, b);
    }
 
    // Method returns minimum number of steps
    // to return to initial array
    static int getMinStepsToSort(int moves[],
                                 int N)
    {
 
        // initially all cells are unvisited
        boolean visit[] = new boolean[N];
        Arrays.fill(visit, false);
 
        // looping over all elements to get
        // various cycle
        int steps = 1;
        for (int i = 0; i < N; i++) {
 
            // if already visited, that
            // means it was a part of some
            // cycle
            if (visit[i])
                continue;
 
            int cycleLen = 0;
 
            // Looping among cycle elements,
            // -1 is for converting value to
            // 0-index based
            for (int j = i; !visit[j];
                 j = moves[j] - 1) {
 
                cycleLen++;
                visit[j] = true;
            }
 
            // Take the lcm of current result
            // and new cycle length
            steps = lcm(steps, cycleLen);
        }
 
        return steps;
    }
 
    // Driver code
    public static void main(String arg[])
    {
        int moves[] = { 4, 5, 1, 3, 2 };
        int N = moves.length;
 
        System.out.print(getMinStepsToSort(
            moves, N));
    }
}
 
// This code is contributed by Anant Agarwal.


Python3
# Python program to get
# minimum steps to return to
# initial array with
# specified movement
 
# Recursive function to
# return gcd of a and b
def  __gcd(a, b):
 
    # Everything divides 0
    if (a == 0 or b == 0):
        return 0
       
    # base case
    if (a == b):
        return a
       
    # a is greater
    if (a > b):
        return __gcd(a-b, b)
    return __gcd(a, b-a)
 
# Utility method to
# get lcm of a and b
def lcm(a, b):
 
    return (a * b) // __gcd(a, b)
 
  
# Method returns minimum
# number of steps to
# return to initial array
def getMinStepsToSort(moves, N):
 
    # initially all cells are unvisited
    visit =[False for i in range(N + 1)]
  
    # looping over all
    # elements to get
    # various cycle
    steps = 1
    for i in range(N):
     
        # if already visited,
        # that means it
        # was a part of some cycle
        if(visit[i]):
            continue
  
        cycleLen = 0
  
        # Looping among cycle
        # elements,  -1 is
        # for converting value
        # to 0-index based
        j = i
        while(not visit[j]):
         
            cycleLen+= 1
            visit[j] = True
            j = moves[j] - 1
     
        # Take the lcm of
        # current result and
        # new cycle length
        steps = lcm(steps, cycleLen)
 
    return steps
 
# Driver code
 
moves = [4, 5, 1, 3, 2]
N = len(moves)
  
print(getMinStepsToSort(moves, N))
 
# This code is contributed
# by Anant Agarwal.


C#
// C# program to get minimum steps to return
// to initial array with specified movement
using System;
 
class GFG {
 
    // Recursive function to return gcd
    // of a and b
    static int __gcd(int a, int b)
    {
        // Everything divides 0
        if (a == 0 || b == 0)
            return 0;
 
        // base case
        if (a == b)
            return a;
 
        // a is greater
        if (a > b)
            return __gcd(a - b, b);
 
        return __gcd(a, b - a);
    }
 
    // Utility method to get lcm of a and b
    static int lcm(int a, int b)
    {
        return (a * b) / __gcd(a, b);
    }
 
    // Method returns minimum number of steps
    // to return to initial array
    static int getMinStepsToSort(int[] moves,
                                       int N)
    {
        // initially all cells are unvisited
        bool[] visit = new bool[N];
 
        // looping over all elements to get
        // various cycle
        int steps = 1;
        for (int i = 0; i < N; i++) {
 
            // if already visited, that
            // means it was a part of some cycle
            if (visit[i])
                continue;
 
            int cycleLen = 0;
 
            // Looping among cycle elements,
            // -1 is for converting value to
            // 0-index based
            for (int j = i; !visit[j];
                j = moves[j] - 1) {
 
                cycleLen++;
                visit[j] = true;
            }
 
            // Take the lcm of current result
            // and new cycle length
            steps = lcm(steps, cycleLen);
        }
 
        return steps;
    }
 
    // Driver code
    public static void Main()
    {
        int[] moves = { 4, 5, 1, 3, 2 };
        int N = moves.Length;
 
        Console.WriteLine(getMinStepsToSort(moves, N));
    }
}
 
// This code is contributed by vt_m.


Javascript


输出:

6