归并排序求逆序对
我们可以这样考虑:
归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。
在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在
前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并
排序中的合并过程中计算逆序数.
题目:http://poj.org/problem?id=1804
C++代码
#include<iostream>
#include<cstring>
using namespace std;
int a[1001],rr[1001],n,tot;
void merge_sort(int l,int r)
{
int mid,i,j,k;
if(l==r) return;
mid=(l+r)/2;
merge_sort(l,mid);
merge_sort(mid+1,r);
i=l;j=mid+1;k=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j]){
rr[k++]=a[i++];
}
else{ //a[i]>a[j]时 则前半部分比a[i]大的数都比a[j]大
tot+=mid-i+1; // 由于此时前半部分a[i]是有序的 则一共有mid-i+1个逆序对
rr[k++]=a[j++];
}
}
while(i<=mid) rr[k++]=a[i++];
while(j<=r) rr[k++]=a[j++];
for (int i=l;i<=r;i++)
a[i]=rr[i];
}
int main()
{
int num=1;
cin>>n;
for (int i=1;i<=n;i++)
{
int n1;
cin>>n1;
memset(a,0,sizeof(a));
memset(rr,0,sizeof(rr));
tot=0; //初始化
for(int i=1;i<=n1;i++)
cin>>a[i];
merge_sort(1,n1);
cout<<"Scenario #"<<num<<endl;
num++;
cout<<tot<<endl;
}
}