POJ2299 Ultra-QuickSort

来源:互联网 发布:三国志9需要优化哪些 编辑:程序博客网 时间:2024/05/18 13:26

A - Ultra-QuickSort
Time Limit:7000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit Status

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 
9 1 0 5 4 ,

Ultra-QuickSort produces the output 
0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

Sample Input

59105431230

Sample Output

60

这道题比较简单,但是必须做归并算法(归并排序),不然是会超时的。
题意为:给出一个无需数列,用 冒泡排序 的方式进行重排,求需要的最小互换次数

冒泡排序:对一个无序数列,我们想将之上升序排列(所谓上升就是指非严格单增)。定义一个指针从第一个值开始走,第二个指针从第一个指针的位置的下一个位置开始走,只要发现比某一个数大的数在这个数的前面,那么互换位置,继续向下搜索。直到最后。

冒排是一种比较粗暴的排序方式,其算法复杂度为O(N^2).但如果是找最小互换次数,有其他的方法。

这就用到了逆序的概念,高等代数课程有提及。在一个排列中,如果位置靠前的数字大于位置靠后的数字,则称这两个数字构成了一个逆序,数列的逆序总数称为“逆序数”。这个问题事实上等价于求逆序数。

 但是啊。。直接粗暴的一个个遍历去求逆序数,这算法复杂度跟冒排是一回事!所以这里求逆序数的方法,是利用归并排序得出。

归并排序的百科级解释参见  归并排序-百度百科  

个人对于归并排序的认识:归并排序,顾名思义,将给出的区间细分,分别得出结果之后再汇总。这是基于分治的思想。分治算法的一个基本要求是:在细分问题的时候,小问题的各个部分都是互不干扰,没有交集的,否则更适合动态规划。

结合代码来看

#include <cstdio>#include <cstring>#define maxn 500010using namespace std;int n,num[maxn],a[maxn];long long ans;void mergsort(int x,int y)//归并排序函数{if(y-x<=1)return;   //先写出递归跳出的条件,实质上是使得int mid=(x+y)/2;    //取中间值:二分mergsort(x,mid);    //递归,前半部分mergsort(mid,y);    //递归,后半部分。这就是把区间无限二分直到本函数第一句的条件成立int p=x,q=mid;      //这句语句以及之后的语句其实都是满足了if之后的那些小区间同时进行的int i=x;            while (p<mid || q<y){if( q>=y || (p<mid && num[p]<=num[q]))a[i++]=num[p++];//读到了正序的数据,将其转入a[]else //这时的关系是:p==mid || num[p]>num[q] {if(p<mid)ans+=(mid-p);//这时num[p]>num[q] ,出现逆序了。ans记下mid-p,即                      //直到mid的值都是大于num[q]的  a[i++]=num[q++];//num[q]较小,因此读入a[]}}for(i=x;i<y;i++)num[i]=a[i];//这时a[]数组已经是排好序了的,如果稍后主函数输出它的话,就会发现}int main(){while(scanf("%d",&n)&&n){memset(num,0,sizeof(num));//两数组置零memset(a,0,sizeof(a));ans=0;for(int i=0;i<n;i++){scanf("%d",&num[i]);}mergsort(0,n);printf("%I64d\n",ans);//下面这段代码是输出归并排序之后的数列的,本题没有这个要求/*for(int i=0;i<n;i++){printf("%d  ",num[i]);}printf("\n");  */}}







0 0
原创粉丝点击