题目链接:传送门
思路:自己的瞎搞的假算法得了8分。。(这里就不贴了),然后看了题解,对于序列中的数字a[i],必定有数占用了他原来的位置,存在一条占用链:如:i 占用 j的位置,j占用k的位置,k占用i的位置。(占用链一定是一个环,应该可以证明)
具体思路就是:因为只能用0交换,如果0不在自己的位置(则0占据了别的数的位置),先通过交换使它在0位置(与它交换的全部的数字都会回到自己的位置),然后看第i个数,是否在自己的位置,如果不在,就把他和0进行交换(让0占据他的位置),然后在下一轮交换进行交换后,会到达合适位置。每轮交换次数是num+1,num是本轮正确排序的数字。(这应该能最小的交换次数)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn] , vis[maxn];
int main() {
int n;
ios::sync_with_stdio(0);
cin >> n;
int cnt = 0 , ans = 0;
for(int i = 0 ; i < n ; i++) {
cin >> a[i];
vis[a[i]] = i;
}
int i = 1;
while(i < n) {
while(vis[0] != 0) {
int t = vis[0];
//swap(a[vis[t]] , a[vis[0]]);
swap(vis[t] , vis[0]);
ans++;
}
if(vis[i] != i) {
ans++;
swap(vis[i] , vis[0]);
//swap(a[vis[i]] , a[vis[0]]);
}
i++;
}
cout << ans << "\n";
return 0;
}