POJ 2299 Ultra-QuickSort

本例主要是利用归并排序求逆序对数

只要在归并排序的基础上添加一行计数即可

View Code
 1 //---------------------------------------
 2 // 利用归并排序(MergeSort)求逆序对数
 3 // http://baike.baidu.com/view/90797.htm
 4 // 归并排序主要采用分治思想,分为若干子序列排序
 5 // 时间空间复杂度和QuickSort相同,但更稳定
 6 //---------------------------------------
 7 #include <cstdio>
 8 #include <cstring>
 9 using namespace std;
10 #define LL long long
11 const int M = 500005;
12 LL a[M], ans, t[M];
13 
14 void MergeSort(LL L, LL R)
15 {
16     // 将序列每相邻两个数字进行归并操作(merge),形成floor(n/2)个序列,排序后每个序列包含两个元素
17     // 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素
18     // 重复步骤2,直到所有元素排序完毕 
19     if (L == R) return;
20     LL mid = (L + R) / 2;
21     MergeSort(L, mid); // 排序左子区间
22     MergeSort(mid + 1, R); // 排序右子区间
23     LL i = L, j = mid + 1, p = 0;
24     // 打印每个待排序区间中所有元素
25     for (LL i = L; i <= R; i++)
26         printf("%d ", a[i]);
27     printf("\n");
28     // 等待左右子区间合并
29     while (i <= mid && j <= R)
30     {
31         if (a[i] > a[j])
32         {
33             // POJ 2299就是在归并排序基础上加这一句
34             // 当a[i]>a[j],a[i]以及以后的数都可以和a[j]形成逆序对
35             ans += mid - i + 1;
36             t[++p] = a[j++]; // a[j]进入合并Merge序列
37         }
38         else
39         {
40             t[++p] = a[i++];
41         }
42     }
43     // 左右子区间剩余元素进入合并序列
44     while (i <= mid) t[++p] = a[i++];
45     while (j <= R) t[++p] = a[j++];
46     // 讲合并序列t赋予a,当前区间结束
47     p = 0;
48     for (LL i = L; i <= R; i++) a[i] = t[++p];
49 }
50 
51 int main()
52 {
53     int n;
54     while (scanf("%d", &n), n)
55     {
56         ans = 0;
57         for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
58         MergeSort(1, n);
59         printf("%lld\n", ans);
60     }
61     return 0;
62 }
63 /*
64 Sample Input:
65 5
66 9 1 0 5 4
67 3
68 1 2 3
69 0
70 */

 

posted @ 2012-07-02 10:22  dgsrz  阅读(142)  评论(0编辑  收藏  举报