您的位置:首页 > 产品设计 > UI/UE

POJ-2299-Ultra-QuickSort

2016-11-28 21:27 232 查看
Ultra-QuickSort

Time Limit: 7000MS Memory Limit: 65536K
Total Submissions: 57709 Accepted: 21326
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
5
9
1
0
5
4
3
1
2
3
0

Sample Output
6
0

Source
Waterloo local 2005.02.05

题解:转的别人的,我觉得对于题意说的很清楚

本题要求对于给定的无序数组,求出经过最少多少次相邻元素的交换之后,可以使数组从小到大有序。

两个数(a, b)的排列,若满足a > b,则称之为一个逆序对。

很明显可以知道,如果相邻的两个元素满足前一个大于后一个,则肯定要交换一次,因为最终位置是小的在前,大的在后。因此本题其实就是求原数组中的逆序对的数目。

求逆序对的数目可以使用归并排序,其实逆序对的数目是归并排序的一个附属产品,只是在归并排序的过程中顺便算出来的。

(2路)归并排序的思想:先把每个数看成一段,然后两两合并成一个较大的有序数组,再把较大的两两合并,直到最后成为一个有序数组。

例如:

初始数组为:4 2 1 3

先把每个数看成一段,即:4 | 2 | 1 | 3

接着两两合并成有序数组,即:2 4 | 1 3

最后合并成总的有序数组,即:1 2 3 4

不难发现,在排序过程中,若某个数向前移动了N位,则必定存在N个逆序数。比如上面第二轮排序中,数字1一开始是在第2位,后面移到了第0位,前进了两位,因此必定存在两个逆序,即(2, 1), (4, 1)。所以只需要在归并排序过程中把这个数记录下来即可得到结果。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>

int n;
long long ans;
int a[500010],b[500010];

void Merge(int l,int mid,int r)//归并并排序
{
int i = l,j = mid+1,k = l;
while(i<=mid && j <= r)//分成两块已经排好的片段排序
{
if(a[i] <= a[j])//如果a[i]的那边比a[j]的小直接记录就好
b[k++] = a[i++];
else
{
ans += j-k;//a[j]肯定比a[k]后面的小,所以逆序数为j-k
b[k++] = a[j++];
}
}
while(i <= mid)
b[k++] = a[i++];
while(j <= r)
b[k++] = a[j++];
for(i = l; i <= r; i++)
a[i] = b[i];
}

void MergeSort(int l,int r)//递归到最小的块
{
if(l < r)
{
int m = (l+r)/2;
MergeSort(l,m);
MergeSort(m+1,r);
Merge(l,m,r);
}
}

using namespace std;
int main()
{
while(~scanf("%d",&n) && n)
{
for(int i = 0; i < n; i++)
scanf("%d",&a[i]);
ans = 0;
MergeSort(0,n-1);
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ-归并排序