题意很简单,求QuickSort最坏情况下的交换次数。理解以后知道应该是一个求序列的逆序对问题。
发现归并排序nlog(n)的排序速度很不错,而求在排序的过程中,有个归并过程merge(),这里是将两个有序数列归并为一个有序数列,在归并的过程中,很容易就能够计算逆序对个数,所以可以很快解决这个问题。
即:对于数列[l, mid] [mid + 1, r]的合并,i 从l开始循环,j从mid + 1开始循环,如果遇到a[i] > a[j] 则出现逆序,可以将a[j]放入辅助数组,同时j++,那么和a[j]逆序的数就有mid-i+1个,因为序列是有序的[i, mid]的所有的数都是大于a[j]的。代码如下。有重温了归并的写法与思想。。
代码
1 #include<stdio.h>
2 #include<string.h>
3 #include<string.h>
4 #include<stdlib.h>
5 #include<math.h>
6
7 #include<iostream>
8 using namespace std;
9
10 #define NN 500004
11 #define NL 1000
12
13 __int64 res;
14 int b[NN]; // 中间辅助数组
15
16 void copy(int a[], int l, int r){
17 int i;
18 for (i = l; i <= r; i++){
19 a[i] = b[i];
20 }
21 }
22 void merge(int a[], int l, int mid, int r){
23 int i = l;
24 int j = mid + 1;
25 int k = l;
26 while(i <= mid && j <= r){
27 if(a[i] < a[j]){
28 b[k++] = a[i];
29 i++;
30 }else{
31 b[k++] = a[j];
32 j++;
33 res += mid - i + 1;
34 }
35 }
36 while(i <= mid){
37 b[k++] = a[i];
38 i++;
39 }
40 while(j <= r){
41 b[k++] = a[j];
42 j++;
43 }
44 }
45
46 void mergeSort(int a[], int l, int r){
47 // 归并排序
48 if(l < r){
49 int mid = (l + r) >> 1;
50 mergeSort(a, l, mid);
51 mergeSort(a, mid + 1, r);
52 merge(a, l, mid, r);
53 copy(a, l, r);
54 }
55 }
56 int main() {
57 int n, i;
58 int f[NN];
59 while(scanf("%d", &n)!= EOF){
60 if(n == 0) break;
61 for (i = 1; i <= n; i++){
62 scanf("%d", &f[i]);
63 }
64 res = 0;
65 mergeSort(f, 1, n);
66 printf("%I64d\n", res);
67 }
68 return 0;
69 }
70