在一个数列中,只能交换相邻的值,求排序该数列需要的最小的交换次数
归并排序,求出每个数的逆序数,(逆序数为该数后面比该数小的元素的个数)
9 1 0 5 4
9的逆序数为4,后面有4个比它小,同理1的逆序数为1,5的逆序数为1
将所有数的逆序数之后求出来,即为交换的最小步数
冒泡直接tle
采用归并排序求逆序数
#include <iostream>
#include <cstdio>
#include <cstring>
#define i64 long long
const int maxN = 500005;
const int inf = 1000000000;
int a[maxN];
int L[maxN];
int R[maxN];
i64 sum;
void merge(int s,int e)
{
int mid = (s+e)>>1;
int len1 = mid+1-s;
int len2 = e-mid;
for(int i = 0;i<len1;i++)
{
L[i] = a[s+i];
}
for(int i = 0;i<len2;i++)
{
R[i] = a[mid+i+1];
}
L[len1] = inf;
R[len2] = inf;
int j=0,k=0;
for(int i = s;i<=e;i++)
{
if(L[j]<=R[k])
{
a[i] = L[j++];
len1--;
}
else
{
a[i] = R[k++];
sum += len1;//此时左边还剩下有len1个数,这些数都比R[k]小,所以R[k]的逆序数为len1
}
}
}
void mergesort(int s,int e)
{
if(s<e)
{
int mid = (s+e)>>1;
mergesort(s,mid);
mergesort(mid+1,e);
merge(s,e);
}
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
for(int i = 0;i<n;i++)
{
scanf("%d",&a[i]);
}
sum = 0;
mergesort(0,n-1);
printf("%lld\n",sum);
}
}