dfs + 最小公倍数 Codeforces Round #383 (Div. 2)

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
")
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
"); 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
");
    else {
        int ans = v[0];
        for (int i = 1; i < v.size(); i++){
            ans = ans * v[i] / gcd(ans, v[i]);
        }
        printf("%d
", ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/heimao5027/p/6142108.html