这道题非常无厘头!
题目描述:
每个学年的开始,高一新生们都要进行传统的军训。今年有一个军训教官十分奇怪,他为了测试学员们的反应能力,每次吹哨后学员们都会变换位置。每次左数第I位学员都会站到第ai个位置,经过若干次之后,队伍又会回到原来的样子。你的任务是计算n个人的队伍至少经过多少次之后,队伍恢复到原来样子。
输入格式:
输入文件的第一位包含一个整数N(0<N10000),表示队伍的人数。
接下来N行,每行一个正整数ai表示左起第i个人接下来出现在左起第ai个位置上。
输出格式
仅包括一行,一个正整数M,表示军官最少的吹哨次数。
样例:
输入:
5
2 3 4 5 1
输出:
5
分析:
这道题大家一拿上就会想到模拟。
那么我们用模拟做一下。
#include<bits/stdc++.h> //我总算掌握万能头文件了
using namespace std;
int main()
{
int n,i,j,o[105],l[105],t[105],flag=0,sum=0,u[105]; //定义所需数组
cin>>n;
for(i=1;i<=n;i++) //初始化数组
{
o[i]=i;
t[i]=i;
u[i]=i;
}
for(i=1;i<=n;i++) //输入变化规律
{
cin>>l[i];
}
while(1) //不知道什么时候结束就用这个
{
for(i=1;i<=n;i++) //变化
{
o[l[i]]=t[i];
}
sum++; //记录变化次数
flag=0; //用于标记是否与原数组相等
for(i=1;i<=n;i++)
{
if(o[i]!=u[i]) //如果与原数组不相等
{
flag++; //标记
}
}
if(flag==0) //没有标记就是与原数组相等
{
cout<<sum;
exit(0); //强力结束!
}
for(i=1;i<=n;i++) //及时更新
{
t[i]=o[i];
}
}
}
当你看到样例过了兴冲冲的提交才发现——————
这么写只能得30分!
(此时的精神状态)
这道题的满分做法是找环再求最小公倍数。
我们仔细观察一下。
我们可以发现:1,2成一个环,3,4,5成一个环。
然后我们把几个环的长度求最小公倍数即可。
#include<bits/stdc++.h> //万能头用上瘾
using namespace std;
int a[100005],o[1000005],w,sum,flag[1000005],b[100005],cnt,gbsh,gys; //好多啊
int main()
{
int i,sum=0,n,j; //这还有几个
cin>>n;
for(i=1;i<=n;i++) //输入
{
cin>>a[i];
}
for(i=1;i<=n;i++) //核心
{
if(flag[i]==0) //如果没有标记 说明还没有成环
{
w=i; //w记录当前位置
sum=1; //第一个位置也算所以初始值是1
flag[w]=1; //当前位置必须标记!
while(1) //熟悉配方
{
if(flag[a[w]]==0) //如果下一个位置没有标记
{
sum++; //环的长度
flag[a[w]]=1; //下一个位置必须标记!
}
else
{
break; //已经有环了跳过
}
w=a[w]; //当前位置更新!
}
cnt++; //环的个数
b[cnt]=sum; //记录环的长度
}
}
//求最小公倍数
for(i=1;i<cnt;i++) //有可能会超出所以是 <cnt
{
//先求最大公因数
for(j=max(b[i],b[i+1]);j>=1;j--)
{
if(b[i]%j==0&&b[i+1]%j==0)
{
gys=j;
}
}
gbsh=b[i]*b[i+1]/gys; //求A与B的最小公倍数方法:A*B÷C (C表示两数的最大公因数)
}
cout<<gbsh<<endl; //这才是最终答案
return 0; //潇洒结束
}
求最大公因数和最小公倍数有种算法叫欧几里得算法,等到学了一定会给大家及时更新!
感谢阅览!欢迎一键三连!欢迎订阅专栏!Thanks♪(・ω・)ノ