时间限制: 1 Sec 内存限制: 128 MB
题目描述
乐乐的 n 位朋友都拥有唯一的一个编号,编号分别为 1 至 n。某天按到达的时间顺序又给了一个顺序号,此时发现顺序号与多数的朋友编号不一致。乐乐想:如果俩俩交换顺序号,使得每位朋友的编号与顺序号相同,则最少需要交换几次?
输入
包含两行:
第一行只有一个正整数:n,表示乐乐朋友的人数
第二行共有 n 个正整数,分别表示按顺序到达的朋友编号
输出
只有一行且只有一个正整数:最少的交换次数
样例输入 Copy
5
4 2 1 5 3
样例输出 Copy
3
提示
对于 30%的数据, 1 <= n <= 100
对于 80%的数据, 1 <= n <= 10 000
对于 100%的数据, 1 <= n <= 100 000
大意:给出一组数据,编号是乱的,两两之间交换(可以不相邻),至少多少次可以使其有序
起初看着像动态规划,就没往下想。结束一交流发现,数据太大,如果是动态规划的话,二重循环肯定超时!
既然不是动态规划,这么大的数据,就要用O(1)的做法了。
思路:对每个不同的数据,直接跳到其归属的位置(调换),而那个位置的值又要跳到其归属的位置,
一直跳,最终,就会跳到一开始那个数据的位置,这样,就构成了一个环。
而这个环的边数,就是最小的调换次数。
对于这组数据中的所有的环,求出边数和就是这组数据调至有序的最少次数。
Code:
#include<iostream>
using namespace std;
const int N=100010;
int n,a[N],t,cnt;
bool f[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]!=i) ;
}
for(int i=1;i<=n;i++){
if(a[i]!=i&&!f[i]){ //找出 编号不同&&不在之前的环中 的一个数据
t=i;
int tt=t;
while(a[tt]!=t){ //跳环
tt=a[tt];
f[tt]=true; //跳过的地方就会变成有序的,标记,下次就不会找到了
cnt++;
}
}
}
cout<<cnt;
return 0;
}
如果哪里不明白或有错误的话,欢迎留言讨论~