10-排序6 Sort with Swap(0, i)(1067)

Sort with Swap(0, i)

1067 Sort with Swap(0, i)

#include <iostream>
#define MAXN 100000
using namespace std;

int main() {
    int pos[MAXN];
    bool used[MAXN];
    int N, num, sort = 0, connected_set = 0; // sort:已排好序的数字 connected_set:“连通集”数量
    cin >> N;
    for( int i = 0; i < N; i++ ) {
        cin >> num;
        pos[num] = i;
        used[num] = false;
        if( i > 0 && pos[num] == num ) { // 除了0, 因为0要用来和其他数交换, 就算在位置0也不能被视为排好序
            used[num] = true;
            sort++;
        }
    }
    for( int i = 0; i < N; i++ )
        if( used[i] == false ) {
            for( num = i; pos[num] != i; num = pos[num], used[num] = true );
            used[num] = true;
            connected_set++;
        }
    cout << (N-sort) - 1 + (connected_set-1);
}

一开始没多想直接模拟这种交换排序,果然就超时了

先讲讲交换排序的思路(注意必须是0和其他数交换

类似贪心的思想,比如0在位置7,就让0和数字7交换,从而7就在正确位置了,以此类推

直到0在位置0时,此时有可能还有其他数字没有排好序

所以只能让0和一个没排好序的数先交换,比如位置1上是数字5,0与5交换

产生一次额外交换,这就是多个连通集的影响(后面讲)

此后再重复最初的步骤,直到0重新到位置0,再检查有没有还没排好序的数字...

于是开始试图找旁门左道

1.首先统计已经在正确位置的数字个数sort,无视这些数字

        总数N - sort

2.计算“连通集”数

第一行为原序列,第二行为从0~N的位置标号

数字  3  5  7  2  6  4  9  0  8  1

位置  0  1  2  3  4  5  6  7  8  9

位置0对应数字3,然后位置3对应数字2,再位置2对应数字7,又位置7对应数字0

形成一个“闭环”,称之为一个“连通集

剩下位置1对应数字5,位置5对应数字4,位置4对应数字6,位置6对应数字9,位置9对应数字1

是另一个“连通集”,然后没有剩下的数字了

一个连通集即整个序列形成闭环,不会对交换次数有影响

此后每多一个连通集,都要额外让0交换一次

      (总数N - sort) + (connected_set -1)

3.计算

最后还要再减一次1

可以这样理解,把N个都不在正确位置的数字逐个放进正确位置需要N步操作

交换也是达到类似这种效果,每次交换让一个数字到正确位置

但是注意最后一次交换可以让两个数字到正确位置,即被交换的数字和0本身!

所以只需要N-1次操作

综上, 交换次数 = (总数N - sort) + (connected_set -1) - 1

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低冷dl

喜欢您来~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值