归并排序求逆序对
归并排序求逆序对
我们知道归并排序是递归的对左右两边区间排序,然后将已经有序的左边区间和右边区间合并。合并的时候,假设左边区间范围是 l <= i < mid 右边的范围是 mid <= j < r ,
如果a[i] <= a[j],那么没有逆序对产生, 如果 a[i] > a[j] ,那么 所有 a[i] .. a[i+i] ... a[mid-1]这些数都是大于a[j]的,因为左边区间已经有序。所以只要每次遇到 a[i] > a[j], ans += mid - i,就能求出所有的逆序对。
题目:http://poj.org/problem?id=1804
源代码
#include <iostream> #include <cstdio> using namespace std; const int maxn = 1111; int a[maxn],tmp[maxn]; int ans; void Merge(int l,int m, int r){ int i=l; int j = m; int k = l; while(i < m && j < r){ if(a[i] > a[j]){ tmp[k++] = a[j++]; ans += m - i ; } 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(r - l > 1){ int m = (l + r) >>1; Merge_Sort(l,m); Merge_Sort(m,r); Merge(l,m,r); } } int main(){ int t; scanf("%d",&t); int cnt = 1; while(t--){ int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); ans = 0; Merge_Sort(0,n); // for(int i=0;i<n;i++) // printf("%d\n",a[i]); printf("Scenario #%d:\n%d\n\n",cnt++,ans); } return 0; }