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

9 篇文章 0 订阅

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 NN nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive NN (10^5) followed by a permutation sequence of {0, 1, ..., N−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


解析:

1、交换的次数最小,那么每次交换都应该把一个数换到它最终应该在的位置(这里把这个数叫做最终数)。

2、0如果在0号位,那么0必须换到一个位置(这个位置上的数不是最终数),这种情况会增加一次无用的交换,但这个交换也是必须的。

3、0不在0号位,那么要把0所在位置的最终数换到这个位置。

4、情况2需要找到0将要换到的位置,这里用set来存储这些位置(如果用遍历数组的方法来找,会超时)

5、情况3需要找到最终数所在的位置,这里使用mapA,即A数组的映射,来快速找到这个位置(用遍历数组的方法,同样会超时)

#include <cstdio>
#include <cstdlib>
#include <set>
using namespace std;
int A[100000], mapA[100000], N;
set<int> s;
void swap( int *a, int *b ) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
int main () {
	int pos_zero, val_sub, pos_sub, cnt = 0;
	scanf("%d", &N);
	for ( int i = 0; i < N; i++ ) {
		scanf("%d", &A[i]);
		mapA[A[i]] = i;		//记录映射
		if ( A[i] != i && i != 0 )  //保存会被交换位置,0不保存(因为0会被多次交换)
			s.insert(i);
		if ( A[i] == 0 )
			pos_zero = i;
	}
	while ( !s.empty() ) {
		if ( pos_zero != 0 ) {   //如果0不在自己的位置上
			val_sub = mapA[pos_zero];
			mapA[ A[pos_zero] ] = val_sub;	//更新映射
			mapA[ A[val_sub] ] = pos_zero;
			swap( &A[pos_zero], &A[val_sub] );
			cnt++;
			s.erase(pos_zero);	//pos_zero上的元素已确定,不会再被交换
			pos_zero = val_sub;		//更新0的位置
		}
		else {
			if ( s.empty() )
				break;
			pos_sub = *s.begin();
			mapA[ A[pos_zero] ] = pos_sub;
			mapA[ A[pos_sub] ] = pos_zero;
			swap( &A[pos_zero], &A[pos_sub] );
			cnt++;
			pos_zero = pos_sub;
		}
	}
	printf("%d", cnt);
	system("pause");
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值