平面上有 nn 个点,编号为 1∼n1∼n。
对于每个点 ii(1≤i≤n1≤i≤n),都存在一条从点 ii 到点 aiai(1≤ai≤n1≤ai≤n,aiai 可以等于 ii)的有向边。
所有边的长度均为 11。
请你判断是否存在一个最小移动距离 tt(t≥1t≥1),使得:
- 我们规定,如果从点 uu 出发,移动 tt 单位长度距离后,到达点 vv,就称点 vv 是点 uu 的目标点。注意,一个点的目标点也可能是它自己。
- 对于图中的每个点 xx,如果点 yy 是点 xx 的目标点,则点 xx 也必须是点 yy 的目标点。
如果存在这样的 tt,请你输出 tt 的最小可能值,否则请你输出 -1
。
输入格式
第一行包含一个整数 nn。
第二行包含 nn 个整数 a1,a2,…,ana1,a2,…,an。
输出格式
如果存在满足条件的 tt(t≥1t≥1),则输出一个正整数,表示 tt 的最小可能值。
否则输出 -1
。
数据范围
前 33 个测试点满足 1≤n≤41≤n≤4。
所有测试点满足 1≤n≤1001≤n≤100,1≤ai≤n1≤ai≤n。
输入样例1:
4
2 3 1 4
输出样例1:
3
输入样例2:
4
4 4 4 4
输出样例2:
-1
输入样例3:
4
2 1 4 3
输出样例3:
1
题意分析:判断一个点走t步走到另外一个点,然后这个另外的点再走t步走到原先的点(可以是本身),也就是给定n个点,n个点能够分别组成环,并且求出一个步数t,表示每个环走t步都能回到起点位置:找到这几个环的长度的最小公倍数即可
(注意:如果环的长度是偶数1->2->3->4那么长度可以减半:1的终点没必要还是1,变成3即可)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=110;
int n;
int a[N];
bool vis[N];
ll gcd(ll x,ll y) { //求最小公因数
if(x<y)return gcd(y,x);
if(!y) return x;//y是0
return gcd(y,x%y);
}
int main() {
cin>>n;
for(int i=1; i<=n; i++) {
cin>>a[i];
}
ll ans=1;//初始化最大公倍数
for(int i=1; i<=n; i++) {
memset(vis,false,sizeof(vis));
int j=a[i];
ll res=1;
vis[i]=true;
while(!vis[j]) {
vis[j]=true;
j=a[j];//j变为下一个可行点
res++;//路径长度++
}
if(j!=i) { //走不到自身
ans=-1;
break;
}
/*偶数,那么环的大小要减半
比如1->2->3->4->1,
那么1的目标点就可以是3,
而不非要是自己
所以路径大小减半。
*/
if(res%2==0) { //路径是偶数
res/=2;
}
if(ans==-1) {
cout<<-1;
return 0;
}
ans=ans/gcd(ans,res)*res;//最大公倍数*最小公因数==a*b
}
cout<<ans;
}