以指定动作返回 {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