经典问题之最少交换次数

题目简述:

此类题目一般概括为:通过交换相邻数来完成排序所需要的最少交换次数。


分析:

显然简单的冒泡排序就是基于这种思想,但是O(n^2)的效率常常无法满足题目要求,我们只能另寻它路。
还是模拟原始做法:

4 8 2 7 5 6 1 3
1 4 8 2 7 5 6 3------>6次

1 2 4 8 7 5 6 3------>2次

1 2 3 4 8 7 5 6------>5次

1 2 3 4 5 8 7 6------>2次

1 2 3 4 5 6 8 7------>2次

1 2 3 4 5 6 7 8------>1次

统计18次

在模拟过程中,我们发现每次都是找到一个最小的然后移到最前面,但是除了这个最小的,其他数的相对次序并没有改变,所以我们可以将原始做法换一种表述方式:

找到最小的,统计它前面有多少个数比它小,然后加入结果,将这个最小的删去。

这时我们就发现,其实原题就是求数列的逆序对的个数!
树状数组。线段树。归并。


参考程序:

#include
#include
using namespace std;
const int maxn=210000;
int n,a[maxn],b[maxn];
int bit(int x){
	return x&(-x);
}
void add(int x){
	while (x<=30){
		b[x]++;
		x+=bit(x);
	}
}
int query(int x){
	int tt=0;
	while (x>0){
		tt+=b[x];
		x-=bit(x);
	}
	return tt;
}
int main(){
	freopen("swapping.in","r",stdin);
	freopen("swapping.out","w",stdout);
	char cmd;
	while (scanf("%c",&cmd)==1)
		a[++n]=cmd-'A'+1;
	int ans=0;
	for (int i=1;i<=n;i++){
		add(a[i]);
		ans+=i-query(a[i]);
	}
	printf("%d",ans);
	return 0;
}


你可能感兴趣的:(经典问题学习笔记)