数组重排 hiho一下第167周

来源:互联网 发布:mac bootcamp磁盘权限 编辑:程序博客网 时间:2024/06/06 17:32

题意:小Hi想知道,如果他每次都按照一种固定的顺序重排数组,那么最少经过几次重排之后数组会恢复初始的顺序?
具体来讲,给定一个1 - N 的排列 P,小Hi每次重排都是把第 i 个元素放到第 Pi个位置上。例如对于 P = (2, 3, 1),假设初始数组是(1, 2, 3),重排一次之后变为(3, 1, 2),重排两次之后变为(2, 3, 1),重排三次之后变回(1, 2, 3)。
被排数组中的元素可以认为是两两不同的。

思路:用暴力试了下超时,所以想其他方法。我们能从排列 P 中看到循环。例如 P = (2, 3, 1),第一位的数移到第二个位置,第二个数移到第三个位置,第三个数移到第三个位置,这样就有一个循环:1->2->3->1。在其他例子中也可能不止有一个循环,我们只要去求这些循环的最小公倍数就行了。

代码:

#include<cstdio>#include<cstring>#include<cstdlib>#include<stack>#include<queue>#include<utility>#include<vector>#include<cmath>#include<set>#include<map>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;int N;int p[110];bool vis[110];int GetGcd(int a, int b){    if(a<b) swap(a, b);    return b==0? a:GetGcd(b, a%b);}int Cal(int a, int b){    return a*b/GetGcd(a, b);}int main(){    //freopen("in.txt", "r", stdin);    while(scanf("%d", &N) == 1){        memset(vis, false, sizeof(vis));        for(int i=0; i<N; i++){            scanf("%d", &p[i]);        }        int ans = 1;        for(int i=0; i<N; i++){            if(!vis[i]){                vis[i] = true;                int tmp = p[i]-1;                int tmpans = 1;                while(!vis[tmp]){                    vis[tmp] = true;                    tmp = p[tmp]-1;                    tmpans++;                }                ans = Cal(ans, tmpans);            }        }        printf("%d\n", ans);    }    return 0;}
原创粉丝点击