您好,欢迎来到爱够旅游网。
搜索
您的当前位置:首页[算法竞赛进阶指南] 超快速排序 (归并排序+逆序对)

[算法竞赛进阶指南] 超快速排序 (归并排序+逆序对)

来源:爱够旅游网
题目

在这个问题中,您必须分析特定的排序算法----超快速排序。

该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序。

对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 5 9。

您的任务是确定超快速排序需要执行多少交换操作才能对给定的输入序列进行排序。

输入格式

输入包括一些测试用例。

每个测试用例的第一行输入整数n,代表该用例中输入序列的长度。

接下来n行每行输入一个整数ai,代表用例中输入序列的具体数据,第i行的数据代表序列中第i个数。

当输入用例中包含的输入序列长度为0时,输入终止,该序列无需处理。

输出格式

对于每个需要处理的输入序列,输出一个整数op,代表对给定输入序列进行排序所需的最小交换操作数,每个整数占一行。

数据范围

0≤N<500000
0≤ai≤999999999

输入样例

5
9 1 0 5 4
3
1 2 3
0

输出样例

6
0

分析:
  • 归并排序求逆序对

  • 第一眼看这个题,发现它就是模仿冒泡排序,假如相邻两个后面一个大于前面一个就交换他们的位置,并且次数减一。但是一看数据量,发现O(n^2)的代码根本不可能通过.

  • 仔细细想交换的次数不就是逆序对数,因为一个数后面有几个比他小的他就会交换几次,所以我们求出逆序对数就好了,而求逆序对数,我们可以使用归并来求,归并排序中当合并的时候,假如后面一个数组的数小的时候我们就可以知道 ,前面一个数组剩下的全部都比他大,所以

    ans+=mid-l+1;
    

具体实现如下。

代码
#include <iostream>
using namespace std;
typedef long long ll;
#define filr(i,a,b) for(i=a;i<=b;i++)
ll n,arr[500005],temp[500005],i,ans;

void merger_sort(ll l,ll r){
	if(r<=l) return ;
	ll mid=(l+r)>>1;
	merger_sort(l,mid);
	merger_sort(mid+1,r);
	ll k=mid+1,t=l,x=l;
	while(x<=mid||k<=r){
		if(k>r||(x<=mid&&arr[x]<=arr[k])){
			temp[t++]=arr[x++];
		}else{
			temp[t++]=arr[k++];
			ans+=mid-x+1;
		}
	} 
	filr(i,l,r) arr[i]=temp[i];
}

int main()
{
	while(cin>>n&&n){
		ans=0;
		filr(i,1,n) cin>>arr[i];
		merger_sort(1,n);
		cout<<ans<<endl;
	}
	return 0;
} 

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- igbc.cn 版权所有 湘ICP备2023023988号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务