Description
In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements
until the sequence is sorted in ascending order. For the input sequence Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
Input
Output
Sample Input
5 9 1 0 5 4 3 1 2 3 0
Sample Output
6 0
本题其实只要是明白了归并排序,至于分治思想和逆排序就很简单了
归并法排序
思想概述:其实归并排序就是分治思想的一种应用,就是每次用二分的方式,每次将序列分成两部分,然后知道分成每一部分两个数为止,
在这一整块作为一部分,依次从该该整区间的左区间第一个数开始和右边(即从mid右面的)第一个数作比较,将小的放到合并序列中
这样就将该小的范围排好序了。之后一次排序,知道当前区间为整个大区间为止(详解http://blog.csdn.net/u014665013/article/details/38035359)
分治思想 http://www.doc88.com/p-98237060283.html
题目本质就是求逆序对了,简单介绍一下。逆序对是指在序列{a0,a1,a2...an}中,若ai<aj(i>j),则(ai,aj)上一对逆序对。而逆序数顾名思义就是序列中逆序对的个数。例如: 1 2 3是顺序,则逆序数是0;1 3 2中(2,3)满足逆序对的条件,所以逆序数只有1; 3 2 1中(1,2)(1,3)(2,3)满足逆序对,所以逆序是3。由定义不能想象,序列n的逆序数范围在[0,n*(n-1)/2],其中顺序时逆序数为 0,完全逆序时逆序数是n*(n-1)/2。
可以利用归并排序时计算逆序个数,时间复杂度是nlog2n,而空间复杂度2n。 利用归并求逆序是指在对子序列s1和s2在归并时,若s1[i]>s2[j](逆序状况),则逆序数加上s1.length-i,因为s1中i后面的数字对于s2[j]都是逆序的。
#include <cstdio>
#include <iostream>
using namespace std;
#define MAX 500001
int n, a[MAX], t[MAX]; //a[]为输入序列 t[]为合并序列 应该注意的是,每次t[]数列都是临时的,
//只在每次当前区间的排序中记录有序序列
__int64 sum; //逆序对个数
// 归并
void Merge(int l, int m, int r)
{
//p指向输出区间
int p = 0;
//i、j指向2个输入区间
int i=l, j=m+1; //2个输入区间都不为空时
while(i<=m && j<=r)
{ // 取关键字小的记录转移至输出区间
if(a[i]>a[j]) //在左边的区间的当前访问的数大于右区间的
{
t[p]=a[j]; //将右区间数合并到合并数列中
p++;
j++; //如果合并了,就将右区间的加1
<span style="color:#ff0000;">sum+=m-i+1; </span> //a[i]后面的数字对于a[j]都是逆序的 例如1(L) 2 7 9 10(mid) 3 4 6 7 8 (r) ^(当前位置)这样在7后面的(当然 小于 =10)的所有数就都大于后面的了所以这样加
}
else //在左边的区间的当前访问的数小于或等于右区间的
{
t[p] = a[i]; //将左区间数合并到合并数列中
p++;
i++;
}
}
while(i <= m) //如果左区间中还存在没有进入合并序列的数,就让剩下的进合并序列
t[p++] = a[i++];
while(j <= r) //如果左区间中还存在没有进入合并序列的数,就让剩下的进合并序列
t[p++] = a[j++];
for (i=0; i<p; i++) // 归并完成后将结果复制到原输入数组
a[l+i] = t[i];
}
// 归并排序
void MergeSort(int l, int r)
{
int m;
if (l<r)
{ // 将长度为n的输入序列分成两个长度为n/2的子序列
m = (l+r)/2;
MergeSort(l, m);// 对两个子序列分别进行归并排序
MergeSort(m + 1, r);
<span style="color:#cc0000;"> Merge(l, m, r);//子序列合并成最终有序序列 //其实完全可以将Merge()函数放在该位置
</span> }
}
int main()
{
int i;
while(1)
{
scanf("%d", &n);
if (n == 0)
break;
sum=0;
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
MergeSort(0, n-1);
printf("%I64d\n", sum);
}
//system("pause");
return 0;
}
浙公网安备 33010602011771号