【题目荟萃】换位置游戏

换位置游戏

时间限制: 1 Sec 内存限制: 128 MB
题目描述
N 个小朋友(编号为 1 到 N)正在玩一个换位置游戏。从左到右依次排列着 N 个凳子 (编号为 1 到 N,最左边的为 1 号凳子,最右边的为 N 号凳子),每个凳子上都有一个数字 (凳脚处红色数字),每个数字互不相同,且都是不超过 N 的正整数。
每轮游戏每个小朋友会做到凳子所写的数字的编号的凳子,求最小轮数让所有人坐到跟自己编号一样的凳子;

输入
输入共 2 行。
第 1 行是一个整数 N(1≤N≤1000),表示参加游戏的小朋友人数,当然也表示凳子的 数目。
第 2 行 N 个互不相同的正整数 Ki(1≤Ki≤N,且 1≤i≤N),Ki 表示第 i 把凳子凳脚处的数字。

输出
输出共 1 行。
表示小朋友们通过换位置后回到游戏开始前坐凳子的状态最少需要经过多少轮。测试数
据保证输出的结果不超出 20000000。

样例输入
复制样例数据
3
1 2 3
样例输出
1

提示
输入有3把凳子。1号凳子凳脚处的数字为1,2号凳子凳脚处的数字为2,3号凳子凳脚处的数字为3。第1轮换位置后,1号小朋友仍然坐在1号凳子上,2号小朋友仍然坐在2号凳子上,3号小朋友仍然坐在3号凳子上。所以经过1轮就回到了游戏开始前状态。
对于60%的数据,1≤N≤500,且最少需要交换的轮数不超过10000。
对于100%的数据,1≤N≤1000,且最少需要交换的轮数不超过20000000。

我利用并查集,找有多少个集合,每个集合的元素个数相当于每个集合中小朋友所要交换的次数,求所有集合的最小公倍数即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<map>
#include<set>
#include<stack>
#include<utility>
#include<queue>
#include<vector>
#include<cctype>
using namespace std;
#define fore(i,a,b) for(int i=a;i<=b;i++)
#define forb(i,a,b) for(int i=a;i>=b;i--)
#define fir first
#define sec second
#define ABS(a) ((a)>0?(a):-(a))
typedef long long ll;
typedef long double ld;
const int MAXN=10005;
int nums[1005];
int fa[MAXN];
int all[MAXN];
int ans[MAXN];
int tot;

int get(int x){
    if(x==fa[x]) return x;
    return fa[x]=get(fa[x]);
}

void merge(int x,int y){
    fa[get(x)]=fa[get(y)];
}

long long gcd(long long x,long long y){
    if(y==0) return x;
    return gcd(y,x%y);
}

long long lcm(long long x,long long y){
    return x/gcd(x,y)*y;
}

int main(){
    int n;
    cin>>n;
    fore(i,1,n) fa[i]=i;
    fore(i,1,n) scanf("%d",&nums[i]),merge(nums[i],i);
    fore(i,1,n) all[get(i)]++;
    fore(i,1,n) if(all[i]) ans[++tot]=all[i];
    fore(i,2,tot) ans[i]=lcm(ans[i-1],ans[i]);
    cout<<ans[tot];
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/rign/p/10352497.html