Given any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to sort them in increasing order. But what if Swap(0, *)
is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:
Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}
Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.
给出数字{0,1,2,...,N-1}中的任一个序列,把他们按递增排序很简单。但是如果只允许使用Swap(0,*)来操作呢。比如说排序{4,0,2,1,3}。我们可以用swap进行如图操作。
现在对于给定的N个非负整数序列排序,你需要找到运用swap的最少次数
Input Specification:
Each input file contains one test case, which gives a positive N (≤10^5) followed by a permutation sequence of {0, 1, ..., N−1}. All the numbers in a line are separated by a space.
每一个测试样例给出一个正数N(≤10^5) 之后跟着一串数字序列{0,1,...,N-1}
Output Specification:
For each case, simply print in a line the minimum number of swaps need to sort the given permutation.
输出排序需要用swap的最少次数
思路:由于必须使用数字0跟其他数进行交换,因此直观上可以想到的策略是:如果数字0当前在i号位,则找到数字i当前所处的位置,把0和i进行交换。
但是在交换过程中,数字0回到了0号位,上面的算法就不能将其与一个确定的数交换。通过该策略,一旦一个非零的数字回到了它原先的位置,在后面的步骤中就不应当再让0去与他交换,否则会让变换次数变多。
如果在交换过程中出现数字0在0号位的情况,就随意选择一个还没有回到"本位"的数字,让其与数字0交换位置。显然,这种交换不会对已经在"本位"的数字产生影响,却使得上面的策略可以继续执行
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100010;
int pos[maxn];//存放各数字当前所处位置编号
int main(){
int n,ans=0;
scanf("%d",&n);
int left=n-1,num;//left存放除0以外不在本位上的数的个数
for(int i=0;i<n;i++){
scanf("%d",&num);
pos[num]=i;//num所处的位置为i
if(num == i&&num!=0){
left--;
}
}
int k=1;//k存放除0之外当前不在本位上的最小的数
while(left>0){
if(pos[0]==0){//如果0在本位上,则寻找一个当前不在本位上的数与0交换
while(k<n){
if(pos[k]!=k){
swap(pos[0],pos[k]);
ans++;
break;
}
k++;
}
}
//只要0不在本位上,就将0所在位置的数的当前所处位置与0的位置交换
while(pos[0]!=0){
swap(pos[0],pos[pos[0]]);
ans++;
left--;
}
}
printf("%d\n",ans);
return 0;
}