首页 > 代码库 > poj1804(归并排序求逆序数)
poj1804(归并排序求逆序数)
逆序数,也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。
我们移动元素的次数转化为,假如对每个数da[i]来说前面比他大的数的数目为c[i]的话,那么移动元素总次数就应该是c[0]+c[1]+……+c[n-1],就是数列的逆序数。
一般解决有两种思路。
1、归并排序,归并排的话一定是最好的方案,主观上想一下每一个数都在向目标位置前进(学过数据结构的话有个名词叫稳定排序,另一个稳定排序是冒泡,选择明显不是)。
2、用线段树树状数组来做,求逆序在另一篇博文中有提。
复杂度来说,先说两种排序,冒泡为O(n^2),归并O(nlog(n)),树状数组也是O(nlog(n)),
代码:
#include<iostream> #include<cstdio> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<cstring> #include<algorithm> #define rep(i,a,b) for(int i=(a);i<(b);i++) #define rev(i,a,b) for(int i=(a);i>=(b);i--) #define clr(a,x) memset(a,x,sizeof a) #define inf 0x3f3f3f3f typedef long long LL; using namespace std; const int mod=1e9 +7; const int maxn=2005; const int maxm=4005; int a[maxn],tmp[maxn]; int ans; void Merge(int l,int m,int r) { int i=l; int j=m+1; int k=l; while(i<=m&&j<=r) { if(a[i]>a[j]) { tmp[k++]=a[j++]; ans+=m-i+1; } else { tmp[k++]=a[i++]; } } while(i<=m)tmp[k++]=a[i++]; while(j<=r)tmp[k++]=a[j++]; for(int i=l;i<=r;i++) a[i]=tmp[i]; } void Merge_sort(int l,int r) { if(l<r) { int m=(l+r)>>1; Merge_sort(l,m); Merge_sort(m+1,r); Merge(l,m,r); } } int main() { int t,n,cas=1; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); ans=0; Merge_sort(0,n-1); printf("Scenario #%d:\n%d\n\n",cas++,ans); } return 0; }
poj1804(归并排序求逆序数)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。