poj2299 Ultra-QuickSort (归并排序)
大致题意:给定一串数字,求冒泡排序需要交换的次数。
分析:一个乱序序列的逆序数=只允许相邻两个元素交换的条件下,得到有序序列的交换次数。
归并排序思想:分治
当我们想把一个数组排序的时候,先把这个数组一分为二,然后左部分一分为二,右部分一分为二...
直到细分到每个部分只有一个元素为止。对他们进行简单的归并,然后到上一级,继续归并(就是递归思想),直到最后完成排序。
归并排序细节:归并排序的分:就是递归把数组分得最小。
合:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到b[k]中,并令i和k分别加上1;
否则将第二个有序表中的元素a[j]复制到b[k]中,并令j和k分别加上1,
如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。
归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点mid二分,接着把左边子区间排序,再把右边子区间排序,
最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。
具体代码:
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=5e5+10;
int a[maxn],b[maxn];
ll sum;
void merge(int l,int mid,int h)
{
int i,j,k;
i=l,j=mid+1,k=l;
while(i<=mid&&j<=h)
{
if (a[i]>a[j])
{
sum+=j-k;
b[k++]=a[j++];
}
else
b[k++]=a[i++];
}
while(i<=mid)
b[k++]=a[i++];
while(j<=h)
b[k++]=a[j++];
for (i=l; i<=h; i++)
a[i]=b[i];
}
void smerge(int l,int h)
{
if (l<h)
{
int mid=(l+h)/2;
smerge(l,mid);
smerge(mid+1,h);
merge(l,mid,h);
}
}
int main()
{
int i,j,n;
while(~scanf("%d",&n)&&n)
{
sum=0;
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
smerge(1,n);
printf("%lld\n",sum);
}
return 0;
}