原题连接:https://pta.patest.cn/pta/test/16/exam/4/question/678
题目如下:
Given any permutation of the numbers {0, 1, 2,..., N−1N-1N−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 NNN nonnegative integers.
Input Specification:
Each input file contains one test case, which gives a positive NNN (≤105le 10^5≤105) followed by a permutation sequence of {0, 1, ..., N−1N-1N−1}. All the numbers in a line are separated by a space.
Output Specification:
For each case, simply print in a line the minimum number of swaps need to sort the given permutation.
Sample Input:
10
3 5 7 2 6 4 9 0 8 1
Sample Output:
9
_________________________________________________________________________________________________________________________________________________________________________________
刚开始看到这个题目没什么思路,就只想到了0应该和它所在位置的元素进行交换……之后参考了陈越老师的讲解,她的思路是得利用在讲“表排序”
中的一个结论,即“N个数字的排列是有若干个独立的环组成”,并结合题目要求,则元素“0”相当于表排序中的“空位”,因此可以进行如下讨论:
(1)如果环是单环,那么表示该元素已经在其正确的位置,无需排序;
(2)如果环是多环(环的元素个数为N0)且包含元素0,0相当于空位,那么每次将0和该位置本来有的元素经行交换,是原来0在的位置上填上正确的元素,那么经过N0-1次交换,即可完成该环内的正
确排序;
(3)如果环为多环(环的元素的个数为Ni)且不包含0,那么先让0和环内任一元素进行交换将0换进来,此时利用(2)中的结论,改环需要进行(Ni+1
)-1次交换即可完成环内的正确排序,但由于把
0换进该环多一次交换,故总的交换次数为Ni+1。
因此,当待排序列的第一个数不为0时,则该序列可分为以上三种环,且(2)环的个数只能为1。设有S个单环,K个多环,则总的交换次数为(N0-1)+(Ni+1)(i从1到K-1),即Ni+K-2(i从1到K),
又Ni(i从1到K)等于N-S,故总的交换次数为:N-S+K-2;
但是,当待排序列的第一个数为0时,那么(2)环的个数为0,(3)环的个数即为K,因此该公式修改为Ni+1(i从1到K),即N-S+K;
除此之外,还应该考虑到待排序列已经正确(包括S==N 和N==1)两种情况,此时输出为0。
1 #include<stdio.h> 2 #define Max 100000 3 4 int main() 5 { 6 int A[Max],Table[Max],flag[Max],N; 7 int i,tmp,S,K; 8 S=K=0; 9 scanf("%d",&N); 10 for (i=0;i<N;i++) 11 { 12 scanf("%d",&A[i]); 13 flag[i]=0; //标识元素访问过了没有 14 } 15 /* 指针数组,用来存放正确的序号 */ 16 for (i=0;i<N;i++) 17 { 18 Table[A[i]]=i; //即元素A[i]存放在序号i中 19 } 20 21 for (i=0;i<N;i++) 22 { 23 if (flag[i]==0) 24 { 25 if (Table[i]!=i) 26 { 27 flag[i]=1; 28 tmp=Table[i]; 29 while(flag[tmp]==0) 30 { 31 flag[tmp]=1; 32 tmp=Table[tmp]; 33 } 34 K++; 35 } 36 else if (Table[i]==i) 37 { 38 flag[i]=1; 39 S++; 40 } 41 } 42 } 43 if (A[0]==0)printf("%d",N-S+K); 44 else if (S==N)printf("0"); 45 else printf("%d",N-S+K-2); 46 return 0; 47 }