poj 2299 Ultra-QuickSort【归并排序求逆序数】

题目大意:

给出长度为n的序列,每次只能交换相邻的两个元素,问至少要交换几次才使得该序列为递增序列。

 

这个题数据量大,虽然给7s的时间,但是冒泡的话肯定超时。

这个题让你求的是逆序数,我们用归并排序来求。

一个乱序序列的 逆序数 在只允许相邻两个元素交换的条件下,得到有序序列的交换次

 


在做这道题前,我参考了《大话数据结构》 编著:程杰 P406, 《c/c++函数与算法速查手册》 编著:陈锐 P582.

View Code
#include<stdio.h>
#include<limits.h>

const int MAXN = 500000 + 10;
const int INF = INT_MAX;

long long tot;//tot为逆序数总数。
int arr[MAXN];

//将b数组中的元素复制到a数组中。
void CopyArray(int a[], int b[], int len, int left)
{
    for(int i = 0; i < len; i++) {
        a[left++] = b[i];
    }
}

//归并排序,合并两个子序列中的元素。
void Merge(int a[], int left, int right)
{
    int begin1, begin2, mid, k=0, len;
    begin1 = left;
    mid = (left+right)/2;
    begin2 = mid+1;
    len = right-left+1;
    int *b = new int[len];
    while(begin1 <= mid && begin2 <= right) {
        if(a[begin1] < a[begin2]) {
            b[k++] = a[begin1++];
        } else {
            b[k++] = a[begin2++];
            tot += (mid - begin1 + 1); 
            //当后面的有序序列中的元素小与前面的有序序列的元素,
            //那么总的逆序数要加上前面有序序列中剩余的元素的个数,
            //因为这些是有序的,所以加上的那些数每个都比后面的序列中参与比较的元素大。
        }
    }
    while(begin1 <= mid) {
        b[k++] = a[begin1++];
    }
    while(begin2 <= right) {
        b[k++] = a[begin2++];
    }
    CopyArray(a, b, len, left);
    delete b;
}

//归并排序。
void Msort(int a[], int s, int t)
{
    int m;
    if( s<t ) {
        m = ( s+t ) /2;
        Msort(a, s, m);
        Msort(a, m+1, t);
        Merge(a, s, t);
    }
}

int main() 
{
    int n;
    while(scanf("%d", &n), n) {
        tot = 0;
        for(int i = 0; i < n; i++) {
            scanf("%d", &arr[i]);
        }
        Msort(arr, 0, n-1);
        printf("%lld\n", tot);
    }
    return 0;
}
posted @ 2012-08-03 22:01  小猴子、  阅读(275)  评论(0编辑  收藏  举报