[數算MOOC]求逆序對(歸併排序)
阿新 • • 發佈:2018-12-30
首先介紹歸併排序,它是指對一個數組,劃分為兩個。對兩個陣列分別排序,兩個陣列排序好後合併。
合併的過程為:從兩個陣列取第一個數,下標i,j,比較,數值比較小的複製到一個輔助陣列中,然後下標++即可。如果有一個數組提前結束,把另外一個數組複製到輔助陣列中。然後把輔助陣列複製給原陣列即完成排序。通過遞迴,很容易實現。
利用歸併排序求逆序對該怎麼求呢?
已經排序好的陣列逆序對為0(廢話)
兩個陣列歸併,如果左陣列中的元素a[i]大於右陣列a[j],歸併陣列則的逆序對+mid-i+1即可(a[i]右面的左陣列元素都大於a[j])
這樣累加即可
題目描述
- 總時間限制:
- 500ms
- 記憶體限制:
- 65536kB
- 描述
-
對於一個長度為N的整數序列A,滿足i < j 且 Ai > Aj.的數對(i,j)稱為整數序列A的一個逆序
<j<=n且ai><j<=n且ai><j<=n且ai><j<=n且ai>請求出整數序列A的所有逆序對個數
- 輸入
- 輸入包含多組測試資料,每組測試資料有兩行
第一行為整數N(1 <= N <= 20000),當輸入0時結束
第二行為N個整數,表示長為N的整數序列 - 輸出
- 每組資料對應一行,輸出逆序對的個數
- 樣例輸入
-
5 1 2 3 4 5 5 5 4 3 2 1 1 1 0
- 樣例輸出
-
0 10 0
上程式碼
#include<iostream> using namespace std; const int maxn=20005; int n; int num[maxn]; int temp[maxn]; int count; void Scanf() { cin >> n; } void Input() { for(int i=0; i<n; i++) cin >> num[i]; } void Merge(int left, int mid, int right) { int index1=left, index2=mid+1; int i=left; for(int j=left; j<=right; j++) temp[j]=num[j]; while(index1<=mid && index2<=right) { if(temp[index1]<=temp[index2]) num[i++]=temp[index1++]; else { num[i++]=temp[index2++]; count+=mid-index1+1; } } while(index1<=mid) num[i++]=temp[index1++]; while(index2<=right) num[i++]=temp[index2++]; } void Merge_sort(int left, int right) { if(left<right) { int mid=(left+right)>>1; Merge_sort(left, mid); Merge_sort(mid+1, right); Merge(left, mid, right); } } void Init() { count=0; } void Print() { cout << count << endl; } int main() { Scanf(); while(n!=0) { Input(); Init(); Merge_sort(0, n-1); Print(); Scanf(); } }