POJ 0809 求逆序对数(归并排序求逆序数)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wr339988/article/details/53946289

题目连接:http://dsa.openjudge.cn/sort/0809/

总时间限制: 500ms    内存限制: 65536kB

描述

对于一个长度为N的整数序列A,满足i < j 且 Ai > Aj.的数对(i,j)称为整数序列A的一个逆序。
请求出整数序列A的所有逆序对个数。

输入

输入包含多组测试数据,每组测试数据有两行
第一行为整数N(1 <= N <= 20000),当输入0时结束
第二行为N个整数,表示长为N的整数序列

输出

每组数据对应一行,输出逆序对的个数

样例输入

5
1 2 3 4 5
5
5 4 3 2 1
1
1
0

样例输出

0
10
0

题意

赤裸裸地求逆序数。。。求逆序数算是算法编程题里常常遇到的问题了,一般情况下求逆序数有三种方法:归并排序、树状数组和线段树。由于博主渣渣还没有学会树状数组和线段树的运用,这里先给出归并排序的解法,待以后再来填这个坑。

AC代码

#include<bits/stdc++.h>
using namespace std;

int n,nums[20005],tmp[20005],cnt;

void mergesort(int l,int r)
{
    if(l>=r)    return;
    int m=(l+r)/2;
    int i=l,j=m+1,k=0;
    while(i<=m&&j<=r){
        if(nums[i]>nums[j]){
            tmp[k++]=nums[j++];
            cnt+=m-i+1;
        }
        else{
            tmp[k++]=nums[i++];
        }
    }
    while(i<=m) tmp[k++]=nums[i++];
    while(j<=r) tmp[k++]=nums[j++];
    for(i=0;i<k;i++)    nums[i+l]=tmp[i];
}

void mergearray(int l,int r){
    if(l>=r)    return;
    int m=(l+r)/2;
    mergearray(l,m);
    mergearray(m+1,r);
    mergesort(l,r);
}

int main()
{
    while(~scanf("%d",&n)&&n){
        cnt=0;
        for(int i=0;i<n;i++){
            scanf("%d",&nums[i]);
        }
        mergearray(0,n-1);
        printf("%d\n",cnt);
    }
    return 0;
}

注意

当时写的时候有好几个点没注意,所以WA了好几次,这里点出来给自己一个提醒。第一是关于归并排序,将左右两个子段合并的时候必须要新开一个O(n)的空间来存储临时数组,否则必须要通过交换元素来达到排序的目的,但是这样会超时。第二是关于逆序数的定义一定要看清,必须要严格满足i < j 且 Ai > Aj,也就是说i < j但是Ai = Aj时是不算逆序数的。

猜你喜欢

转载自blog.csdn.net/wr339988/article/details/53946289
今日推荐