先说说题目想让我们干什么:
给定一个从1到n的数字排列,我们总是可以通过交换数字对来获得序列1,2,3,…,n 例如,如果初始序列为2、3、5、4、1,我们可以按以下方式对其进行排序:
2 3 5 4 1
1 3 5 4 2
1 3 2 4 5
1 2 3 4 5
在这里三个交换被用过。给定特定的排列,我们至少需要进行多少次交换。
https://vjudge.net/problem/POJ-1674
清楚题意了,这里给出两种做法:
一般思路是从头遍历,只要数字所在位置不对,我们在后面找到该位置主人与之交换,交换一次ans++即可
这里给出核心代码:
int ans = 0;
for(int i = 1; i <= n ; i++) {
if(a[i] == i) continue;
for(int j = i + 1; ; j++)
if(a[j] == i) {
swap(a[i], a[j]);
ans++; break;
}
}
/但效率是个问题,上述代码搜索时间过长,耗时 250ms
/下面给出另一种方法,耗时 < 50ms 核心代码如下:
int a[maxn], p[maxn];
int n; scanf("%d",&n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
p[ a[i] ] = i;//p 存 数字所在下标
}
int ans = 0;
for(int i = 1; i <= n ; i++)
if(i != a[i]) {
p[a[i]] = p[i];//注意p[i]无需同步,因为不会再用到
swap(a[i], a[p[i]]);
ans++;
}