歸併排序的經典-求逆序對

江上舟搖發表於2022-07-12

本來今天poj崩掉了,並且求逆序對也是個很簡單的問題,羅黑上的分治的題也都刷完了(其實難得一見上羅黑的練習題上的簡單題目),東哥的題又刷不動,打算今天就到這了

但是一想到以前也沒有總結過逆序對的求法,寫完這個總結在做一道每日一題就休息了;

先認識一下什麼是逆序對,舉一個例子:

 

上述寫的夠清楚了吧(電腦寫字很爛,見諒)

歸併排序我相信不用多介紹了吧?都相信已經學了,算了,要不概括一下歸併排序的核心吧:

歸併排序的核心其實就是先將每個元素初始化為子集,兩兩子集合並,實現內部排序,一直這樣處理知道最後剩下一個集合

稍微說一下合併:

要歸併兩個有序的子序列

例如我們要歸併a[]={13,94,99},{34,56}這兩個子序列

 

 將i,j分別指向子序列的第一個數,進行一次比較發現a[i]<a[j],則將a[i]放在輔助陣列b中,經過四次比較

最終可得b[]={13,34,56,94,99}

第二次比較

 

 第三次比較

 

 第四次比較

 

 具體來看題目:

http://acm.hdu.edu.cn/showproblem.php?pid=4911

題目大意:

給定一個陣列,交換相鄰任意兩個元素,且不超過k次,求最少的逆序對有多少?

題目分析:當k=0的時候即求原始陣列中有多少對逆序對,並且在每次合併中,如果子序列內部是有序的則不存在逆序對;

在合併兩個子序列時,若前子序列的元素大於後子序列的元素則產生逆序對,像上面四次合併,並且在每次合併的時候,可能出現不止一對逆序對,

例如在第二次合併的時候,就出現了{34,96},{34,99}兩對逆序對

那分別討論原始陣列中的逆序對cnt,若cnt<=k則說明不夠交換k次,即最少逆序對為0對

若cnt>k則說明k次交換都發生在逆序的相鄰元素上,則有最少cnt-k對

解題思路:分治法,歸併排序

難度評價:易

參考程式碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
 5 const int N=1e5+10;
 6 int a[N];
 7 int b[N];
 8 int cnt;
 9 int n,k;
10 void Merge(int L,int mid,int R)
11 {
12     //歸併
13     int i=L;
14     int j=mid+1;
15     int t=0;
16     while(i<=mid&&j<=R)
17     {
18         if(a[i]>a[j])
19         {
20             b[t++]=a[j++];
21             cnt+=mid-i+1;//出現逆序對
22         }
23         else
24             b[t++]=a[i++];
25     }
26     //檢查
27     //一個子序列中的數都處理完了,另一個還沒有,把剩下的複製過來
28     while(i<=mid)
29         b[t++]=a[i++];
30         while(j<=R)
31             b[t++]=a[j++];
32         //陣列拷貝
33         for(int i=0;i<t;i++)
34             a[L+i]=b[i];
35 }
36 void mergesort(int low,int high)
37 {
38     if(low<high)
39     {
40         int mid=(low+high)/2;
41         //
42         mergesort(low,mid);
43         mergesort(mid+1,high);
44         //
45         Merge(low,mid,high);
46     }
47 }
48 signed main()
49 {
50     IOS;
51     while(cin>>n>>k)
52     {
53         cnt=0;
54         for(int i=0;i<n;i++)
55         {
56             cin>>a[i];
57         }
58         mergesort(0,n-1);
59         if(cnt<=k)
60             cout<<0<<endl;
61         else
62             cout<<cnt-k<<endl;
63     }
64 }

 

相關文章