Sort with Swap(0, i)

原题连接:https://pta.patest.cn/pta/test/16/exam/4/question/678

题目如下:

Given any permutation of the numbers {0, 1, 2,..., N−1N-1N1}, 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 (≤105\le 10^5105​​) followed by a permutation sequence of {0, 1, ..., N−1N-1N1}. 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 }

 

 
posted @ 2016-12-20 12:39  变通无敌  阅读(1233)  评论(0编辑  收藏  举报