hihoCoder1330—数组重排

来源:互联网 发布:极限编程和瀑布模型 编辑:程序博客网 时间:2024/06/05 14:52

题目链接:传送门

题目1 : 数组重排

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi想知道,如果他每次都按照一种固定的顺序重排数组,那么最少经过几次重排之后数组会恢复初始的顺序?

具体来讲,给定一个1 - N 的排列 P,小Hi每次重排都是把第 i 个元素放到第 Pi个位置上。例如对于 P = (2, 3, 1),假设初始数组是(1, 2, 3),重排一次之后变为(3, 1, 2),重排两次之后变为(2, 3, 1),重排三次之后变回(1, 2, 3)。

被排数组中的元素可以认为是两两不同的。

输入

第一行一个整数 N ,代表数组的长度。 (1 ≤ N ≤ 100)

第二行N个整数,代表1 - N 的一个排列 P 。

输出

输出最少重排的次数。

样例输入
32 3 1
样例输出
3
解题思路:每个数字都会有各自的循环周期,我们只要求出各循环周期的最小公倍数。我们可以求出序列的所有循环节,然后求其长度的最小公倍数。


#include <iostream>#include <cstdio>#include <algorithm>#include <cstdlib>#include <cstring>using namespace std;const int N = 150;int data[N],tick[N];int gcd(int a,int b){if(b == 0) return a;else return gcd(b,a%b);}int lcm(int a,int b){return a/gcd(a,b)*b;}int solve(int u){int cnt  = 1,v = u;tick[u] = 1;while(1){v = data[v];tick[v] = 1;cnt++;if(data[v] == u) break;}return cnt;}int main(){int n;while(~scanf("%d",&n)){memset(tick,0,sizeof(tick));for( int i = 1 ; i <= n ; ++i ){scanf("%d",&data[i]);}int ans = 1;for( int i = 1 ; i <= n ; ++i ){if(!tick[i]){ans = lcm(ans,solve(i));} }printf("%d\n",ans);}return 0;}