7-16 Sort with Swap(0, i)(25 分)

7-16 Sort with Swap(0, i)(25 分)

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 (≤10^5) 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个数字的排列由若干独立的环组成的知识。

1.单元环swap(0,i)次数为0;

2.有0的非单元环,swap(0,i)次数为n-1;

3.无0的单元环,可以先把环里随便一个数和0交换一次,这样整个环就变成了含0的n+1个元素的非单元环,根据前面的情况2,次数为(n+1)-1,但还要加上把0换进去的那次,故swap(0,i)次数为n+1;

代码如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int flag=0; // 记录circle是否含0;
int main(){
    int N; cin>>N;
    // 储存数列
    vector<int> sequence; 
    
    // 为了已知元素找下标而建立的position集合
    // 其中pos[i]表示sequence中数值为i的元素的下标为pos[i]
    vector<int> pos;   
    
    sequence.resize(N); // 不能少,为sequence创造N个空间
    pos.reserve(N); // 不能少
    
    //读入数据和初始化pos
    for(int i=0;i<N;i++) {
        scanf("%d",&sequence[i]);
        pos[sequence[i]]=i;
    }
    
    //temp储存circle中第一个位置的元素
    //swap_times记录swap(0,i)的次数
    //elements_num记录circle中元素的个数
    int temp,swap_times=0,elements_num=0;
    for(int element=0;element<N;element++){
    
    //temp0用来进行下面的赋值活动
        int element_circle=element; int temp0;
        temp=sequence[element_circle];
        
        //每次进入circle前初始化elements_num为0;
        elements_num=0; 
        //若为单元环,则不进入while,故elements_num为0;
        
        while(pos[element_circle]!=element_circle){//判断当前位置sequence[i]是否为i,即是否是单元环和环是否结束;若不是,则继续
        
            if(sequence[element_circle]==0)        
            flag=1;//记录该circle是否有0 
            elements_num++; // 记录circle元素个数
            if(pos[pos[element_circle]]!=pos[element_circle])//用于判断当前元素是否环的尾巴
            sequence[element_circle]=element_circle; //不是尾巴
            else
            sequence[element_circle]=temp;// 是尾巴,用temp来赋值
            
            //下面部分用来更新pos和移动element_circle
            temp0=element_circle;
            element_circle=pos[element_circle];
            pos[temp0]=temp0;
            //
            }
        if(elements_num!=0){ // 判断是否是单元环
        if(flag==1) swap_times+=elements_num-1; //判断circle是否有0,有0的非单元环移动elements-1次
        else swap_times+=elements_num+1; //无0的非单元环移动elements+1次
        }
        
        //归零flag和elements_num
        flag=elements_num=0;
    }
    cout<<swap_times<<end;
    return 0; 
}

webwxgetmsgimg?&MsgID=8462467736741321962&skey=%40crypt_3f9939b1_8b0687212e21a68ec8e45333b8f7de4f

转载于:https://www.cnblogs.com/A-Little-Nut/p/8067017.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值