题目链接
http://codeforces.com/contest/742/problem/C
思路
C的题意当时没读懂= =其实就是求一个数x,使对图中的所有点,a出发经过x能到b,b再经过x能回到a。其实就是能成环
首先判断无解的情况:
对于图中的所有点,有且仅有一条出边,那么如果能成环,那么将有且仅有一条入边,若不满足,则无解
有解情况讨论:
如果环为长度为k的奇环,那么得经过k(只能回到自己)
如果环为长度为k的偶环,那么只需要经过k / 2
则先跑强连通分量对所有点编号,得到所有环的长度,然后求它们的最小公倍数即可
细节
注意开long long
代码
#include <bits/stdc++.h>
using namespace std;
inline int in() {int x; scanf("%d", &x); return x;}
#define pr(x) {cout << #x << ' ' << x << endl;}
#define LL long long
const int maxn = 100 + 5;
int n, num[maxn];
int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
stack<int> S;
vector<int> G[maxn];
void dfs(int u) {
pre[u] = lowlink[u] = ++dfs_clock;
S.push(u);
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!pre[v]) {
dfs(v);
lowlink[u] = min(lowlink[u], lowlink[v]);
} else if (!sccno[v]) {
lowlink[u] = min(lowlink[u], pre[v]);
}
}
if (lowlink[u] == pre[u]) {
scc_cnt++;
for(;;) {
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
if (x == u) break;
}
}
}
void find_scc() {
for (int i = 1; i <= n; i++) {
if (!pre[i]) dfs(i);
}
}
int cnt[maxn];
void solve() {
for (int i = 1; i <= n; i++) cnt[sccno[i]]++;
for (int i = 1; i <= scc_cnt; i++) {
if (cnt[i] % 2 == 0) cnt[i] /= 2;
}
LL lcm = cnt[1], g = 1;
for (int i = 1; i < scc_cnt; i++) {
LL v = cnt[i + 1];
g = __gcd(lcm, v);
lcm = lcm * v / g;
}
cout << lcm << endl;
}
int main() {
n = in();
for (int i = 1; i <= n; i++) {
int x = in();
G[i].push_back(x);
num[x]++;
num[i]++;
}
for (int i = 1; i <= n; i++) {
if (num[i] != 2) {
cout << -1 << endl;
return 0;
}
}
find_scc();
solve();
return 0;
}