http://codeforces.com/contest/742/problem/C
题目大意:从x出发,从x->f[x] - > f[f[x]] -> f[f[f[x]]] -> ..... -> y的步数需要t步,然后再从y出发回到x的步数也需要t步。问需要找到一个最小的t,使得任何一个x经过t步可以到达某一个y,且y也可以经过t步走到x
思路:
先判断是否全都是自环。然后如果不是全都是自环的话。再dfs找环,并且记录环中的结点数。如果是偶环,那么往vector里面push_back(结点数/2),奇环就往vector里面push_back(结点数)。然后求最小公倍数就好啦。
当然,要判断是否有不存在环的情况
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #pragma comment(linker,"/STACK:102400000,102400000") #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha\n") const int maxn = 100 + 5; int crush[maxn], vis[maxn]; int n; vector<int> v; int gcd(int a, int b){ return b == 0 ? a : gcd(b, a % b); } bool dfs(int u, int &cnt, int beg){ vis[u] = true; int v = crush[u]; if (v == beg) return false; if (vis[v]) return true; cnt += 1; return dfs(v, cnt, beg); } int main(){ cin >> n; int t = 0; for (int i = 1; i<= n; i++){ scanf("%d", crush + i); if (i == crush[i]) t++; } if (t == n) { printf("1\n"); return 0; } bool flag = false; for (int i = 1; i <= n; i++){ if (i == crush[i]) continue; if (!vis[i]) { int cnt = 1; flag = dfs(i, cnt, i); if(flag) break; v.push_back(cnt % 2 == 0 ? cnt/2 : cnt); } } if (flag) printf("-1\n"); else { int ans = v[0]; for (int i = 1; i < v.size(); i++){ ans = ans * v[i] / gcd(ans, v[i]); } printf("%d\n", ans); } return 0; }