中国大学MOOC-陈越、何钦铭-数据结构-10-排序6 Sort with Swap(0, i)

转载自http://blog.sina.com.cn/s/blog_ce1b01420102visv.html

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.

Input Specification:

Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, ..., N-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
-----------------------------------------------------------------------------------------------------------------------------------------------
本题比较水,几行代码就解决了,但需要用到表排序的一些知识。 
预备知识:N个数字的排列有若干个独立的环组成。其中N个数字表示1~N或者0~N-1等类似递增的数列。
根据题意,我选取了3个数字(0,1,2)的排列进行分析 
 
08-3. <wbr>Sort <wbr>with <wbr>Swap(0,*) <wbr>(25)

关于环的解释:
假定数组内存放的是下个数组的下标,已021为例,A[0]=0,刚好指向自己,所以0是只含1个元素的环,A[1]=2 指向下标为2的元素,而A[2]=1,指向下标为1的元素,所以,A[1]和A[2]组成了一个环 。
分析:
     第一种情况:所有的单个数字都是独立的环,例如012三个数字已经排好了位置,也就是说如果独立环就1个元素就不需要交换位置。
     第二种情况:N个数字组成了1个环,例如201和120。发现都需要2次交换排成012,猜想:交换次数 = 环的元素个数 - 1。
     第三种情况: 有2个环,分别是021、102、210。每种情况都是有1个含有1个元素的环和含有2个元素的环组成的,按第1和第2种情况猜测,1个元素的环不需要交换,含有2个环的需要交换一次,所以结论应该都是1次交换,而实际情况102和210确实是1次,021却是3次。
为什么021会不同?那是因为Swap(0,*)是跟0相关的操作,而0一开始就站在了应该待的位置,如果0不动,后面2个元素是没法移动的。为了能使这种情况也变成一般性,我们需要先把0和后面任意元素交换位置,即把0加入到其他环中,对一个含有N个元素的环来说,随着0的加入,就变成了N+1个元素的环,然后就可以按普通情况来处理了,对N+1个元素的环,总共需要移动N次,加上第一步0和环中任意元素交换的那一次,总共需要N + 1次。
     按上面粗略的分析,这道题就可以看成判断独立数环的问题。如果环中只含有1个元素,则不需要交换;如果有N个元素的环且包含0,则需要移动N - 1次;
如果N个元素且不包含0,需要移动N + 1次。题目要求出最少次数,所以并不需要模拟移动,只需判断环有几个元素组成,是否包含0即可。

==================================================================
#include < cstdio >

int *A;

int Cal(int A[], int i, int N); //计算需要交换几次

int main()
{
    int N;
    int Total = 0;
    scanf("%d", &N);
    A = new int[N];
    for(int i = 0; i < N; i++)
        scanf("%d", &A[i]);
    for(int i = 0; i < N; i++){
        if (A[i] == i) continue;    //数环只含1个元素
        int S = Cal(A, i, N);       //以i为环的起点进行扫描
        Total += S;                 //更新交换的次数
    }
    printf("%d\n", Total);

    return 0;
}

int Cal(int A[], int i, int N)
{
    int S = 0;
    bool Flag = false;              //用来判断是否含0
    while(A[i] != i){               //被访问过的元素下标=元素值
        if (i == 0) Flag = true;
        int t = i;                  //保存原始下标
        i = A[i];                   //让i指向下一个元素的下标
        A[t] = t;                   //访问过的元素做记号
        S++;
    }
    if (Flag) return S - 1;         //含有0
              else  return S + 1;   //不含0
}


 
 
 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值