POJ 2299 Ultra-QuickSort [归并排序做法]
2016-08-18 20:46
417 查看
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
Sample Output
Source
Waterloo local 2005.02.05
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
顺便写个归并排序的做法,以前其实有写过,找不到了……
注意a[ ],rs[ ]和tot都要开成long long型的,不然会WA……
#include<cstdio>
#include<cstring>
int n;
long long a[500005],rs[500005],tot;
void merg(int l,int r)
{
if(l==r) return;
int m=(l+r)/2;
int i=l,j=m+1,k=l;
merg(l,m);
merg(m+1,r);
while((i<=m) && (j<=r))
{
if(a[i]<=a[j]) rs[k++]=a[i++];
else
{
tot+=j-k;
rs[k++]=a[j++];
}
}
while(i<=m) rs[k++]=a[i++];
while(j<=r) rs[k++]=a[j++];
for(int i=l;i<=r;i++) a[i]=rs[i];
}
int main()
{
while(scanf("%d",&n)!=EOF && n)
{
tot=0;
memset(a,0,sizeof(a));
memset(rs,0,sizeof(rs));
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
merg(1,n);
printf("%lld\n",tot);
}
return 0;
}
下面一段来自神犇Onlyan的博客,解释得很棒,就贴过来了(没有全部贴不算转载吧……[逃)
本题要求对于给定的无序数组,求出经过最少多少次相邻元素的交换之后,可以使数组从小到大有序。
两个数(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)。所以只需要在归并排序过程中把这个数记录下来即可得到结果。
(原网页:http://blog.csdn.net/alongela/article/details/8119209)
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[ ],rs[ ]和tot都要开成long long型的,不然会WA……
#include<cstdio>
#include<cstring>
int n;
long long a[500005],rs[500005],tot;
void merg(int l,int r)
{
if(l==r) return;
int m=(l+r)/2;
int i=l,j=m+1,k=l;
merg(l,m);
merg(m+1,r);
while((i<=m) && (j<=r))
{
if(a[i]<=a[j]) rs[k++]=a[i++];
else
{
tot+=j-k;
rs[k++]=a[j++];
}
}
while(i<=m) rs[k++]=a[i++];
while(j<=r) rs[k++]=a[j++];
for(int i=l;i<=r;i++) a[i]=rs[i];
}
int main()
{
while(scanf("%d",&n)!=EOF && n)
{
tot=0;
memset(a,0,sizeof(a));
memset(rs,0,sizeof(rs));
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
merg(1,n);
printf("%lld\n",tot);
}
return 0;
}
下面一段来自神犇Onlyan的博客,解释得很棒,就贴过来了(没有全部贴不算转载吧……[逃)
本题要求对于给定的无序数组,求出经过最少多少次相邻元素的交换之后,可以使数组从小到大有序。
两个数(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)。所以只需要在归并排序过程中把这个数记录下来即可得到结果。
(原网页:http://blog.csdn.net/alongela/article/details/8119209)
相关文章推荐
- poj 2299 Ultra-QuickSort 线段树求逆序数+离散化||归并排序求逆序数
- POJ 2299 Ultra-QuickSort 【归并排序 || 树状数组求逆序对数】
- POJ 2299 Ultra-QuickSort 【归并排序求逆序数 OR 树状数组求逆序数】
- POJ 2299 Ultra-QuickSort 【归并排序求逆序对数】
- POJ 2299 Ultra-QuickSort | 归并排序
- POJ 2299 Ultra-QuickSort [树状数组做法]
- poj 排序相关之2299 Ultra-QuickSort
- poj 2299 Ultra-QuickSort 初级->数据结构->排序-归并排序
- POJ 2299 Ultra-QuickSort (排序+数据离散化+求顺序数)
- POJ-2299 Ultra-QuickSort-分治法排序求交换速度
- poj 2299 Ultra-QuickSort (归并求逆序数)
- POJ 2299 Ultra-QuickSort 快速排序求逆序对
- poj 2299 Ultra-QuickSort 归并排…
- poj 2299 Ultra-QuickSort
- POJ 2299, Ultra-QuickSort
- 2299-Ultra-QuickSort-交换相邻两个数排序-求逆序对个数-合并排序
- POJ 2299 Ultra-QuickSort 归并排序
- poj 2299 Ultra-QuickSort
- POJ2299 Ultra-QuickSort(归并排序)
- [普及] 求序列中逆序对的个数 [poj 2299 Ultra-QuickSort]