练习题 POJ2299的两种解法 树状数组/归并排序

Poj 2299 统计如果要对一串数据排序,冒泡排序需要交换多少次

即求逆序数,可以用树状数组或者归并排序求取。

 1 //Poj 2299 树状数组解法
 2 #include <stdio.h>
 3 const int N = 500005;
 4 struct Node{
 5     int val;
 6     int pos;
 7 } pool[N];
 8 int c[N], reflect[N], n;
 9  
10 int lowbit(int x){
11     return x & (-x);
12 }
13 void update(int x){
14     while (x <= n){
15         c[x] += 1;
16         x += lowbit(x);
17     }
18 }
19 int getsum(int x){
20     int sum = 0;
21     while (x > 0){
22         sum += c[x];
23         x -= lowbit(x);
24     }
25     return sum;
26 }
27 int main(){
28     while (scanf("%d", &n) != EOF && n){
29         for (int i = 1; i <= n; ++i){
30             scanf("%d", &pool[i].val);
31             pool[i].pos = i;
32         }
33         qsort(1, n);   //排序
34         for (int i = 1; i <= n; ++i) reflect[pool[i].pos] = i;   //离散化
35         for (int i = 1; i <= n; ++i) c[i] = 0;   //初始化树状数组
36         long long ans = 0;
37         for (int i = 1; i <= n; ++i){
38             update(reflect[i]);
39             ans += i - getsum(reflect[i]);
40         }
41         printf("%lld\n", ans);
42     }
43     return 0;
44 }
45 void qsort(int s, int t){
46     int l = s, r = t;
47     Node tmp = pool[s];
48     pool[s] = pool[l];
49     while (true){
50         while ((r > l) && (pool[r].val >= tmp.val))--r;
51         if (r <= l)break;                  //再也找不到比tmp小的数
52         pool[l] = pool[r];
53         while ((l < r) && (pool[l].val <= tmp.val))++l;
54         if (l >= r)break;
55         pool[r] = pool[l];
56     }
57     pool[l] = tmp;
58     if (s < --l)qsort(s, l);
59     if (t > ++r)qsort(r, t);
60 }


 

/*POJ 2299 归并排序解法

求逆序对的数目可以使用归并排序,其实逆序对的数目是归并排序的一个附属产品,只是在归并排序的过程中顺便算出来的。

(2路)归并排序的思想:先把每个数看成一段,然后两两合并成一个较大的有序数组,再把较大的两两合并,直到最后成为一个有序数组。例如:

初始数组为:4 2 1 3

先把每个数看成一段,即:4 | 2 | 1 | 3

接着两两合并成有序数组,即:2 4 | 1 3

最后合并成总的有序数组,即:1 2 3 4

*/

 1 #include <stdio.h>
 2 long long num[500005];
 3 long long temp[500005];
 4 int n;
 5 long long ans;
 6  
 7 void merge(int low, int mid, int high){
 8     int i = low, j = mid + 1, k = low;
 9     while (i <= mid && j <= high){
10         if (num[i] <= num[j]){
11             temp[k++] = num[i++];
12         }
13         else{
14             ans += j - k; //统计逆序,需要交换的次数
15             temp[k++] = num[j++];
16         }
17     }
18     while (i <= mid) temp[k++] = num[i++];
19     while (j <= high) temp[k++] = num[j++];
20     for (i = low; i <= high; ++i){
21         num[i] = temp[i];
22     }
23 }
24 void mergeSort(int a, int b){
25     if (a < b){
26         int mid = (a + b) / 2;
27         mergeSort(a, mid);
28         mergeSort(mid + 1, b);
29         merge(a, mid, b);
30     }
31 }
32  
33 int main(){
34     while (scanf("%d", &n) != EOF && n > 0){
35         ans = 0;
36         for (int i = 0; i < n; ++i)
37             scanf("%lld", num + i);
38         mergeSort(0, n - 1);
39         printf("%lld\n", ans);
40     }
41     return 0;
42 }

 

posted @ 2017-12-28 16:47  proscientist  阅读(206)  评论(0编辑  收藏  举报