时间限制:
10000ms
单点时限:
1000ms
内存限制:
256MB
-
3 2 3 1
样例输出
-
3
描述
小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 。
输出
输出最少重排的次数。
具体思路可以看题目分析区,都是大神,这里说一说我走过的坑
第一种思路:定义好要重排的数a[101],定义为1-100,按照给定的规则P,进行死循环,对a内容进行修改,每次修改后,判断与原始数据 是否相同,相同则输出操作次数。这样计算下来,可以得到输出结果,但是时间复杂度太高,有O(2*n^2),90,无法AC
#include<iostream>
#include<string>
using namespace std;
int main()
{
//freopen("input.txt","r",stdin);
int a[101],b[101],p[101],A[101];
int i,j,n,flag;
cin>>n;
for(i=1;i<=n;i++)
{
a[i]=i;
A[i]=i;
}
for(i=1;i<=n;i++)
{
cin>>p[i];
}
i=0;
while(1)
{
i++;
flag=0;
for(j=1;j<=n;j++)
{
b[p[j]]=a[j];
}
for(j=1;j<=n;j++)
{
a[j]=b[j];
if(b[j]!=A[j]){flag=j;}
}
if(flag==0)break;
}
cout<<i<<endl;
return 0;
}
第二种思路,参照讨论区的方法,a[101]中每一个数都是一个操作循环结,针对每一个数,按P规则修改,记录每个数需要的操作次数,求所有数的最小公倍数。时间复杂度为O(n^2),方法已AC。
#include<iostream>
#include<string>
using namespace std;
int mul(int a,int b)
{
int max,i;
if(a>b)max=a;
else max=b;
for(i=max;i<=a*b;i++)
{
if(i%a==0&&i%b==0)return i;
}
}
int CalmaxNum(int num[],int length)
{
int i;
for(i=0;i<length-1;i++)
{
num[i+1]=mul(num[i],num[i+1]);
}
return num[length-1];
}
int main()
{
//freopen("input.txt","r",stdin);
int b[101],p[101];
int i,j,n,count;
b[0]=1;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>p[i];
}
for(i=1;i<=n;i++)
{
j=i;
count=0;
while(1)
{
count++;
i=p[i];
if(i==j)
{
b[j]=count;
break;
}
}
}
cout<<CalmaxNum(b,n)<<endl;
return 0;
}