歸併排序加例題

Tiny_W發表於2018-03-18

歸併排序,採用的是分治的思想,例如:

0 4 2 1 3

這個陣列,先分成兩部分

0 4 和 2 1 3

再分成兩部分

0  和  4  和  2   和  13

最後則

0 和 4 和 2 和 1 和  3

然後, 建立新陣列

0 和 4,0小於4

則新陣列為0 4

同理可得  1  3

則可得0 4 和 2 和 1 3

再建立新陣列,對比0  4 和 2

顯然,0 小於2,新陣列0

再對比4 和2,2 小於4,則新陣列0 2

最後剩下個4,則新陣列0 2 4

再對比0 2 4 和 1 3 

原理同上,最後得到

0 1 2 3 4


給一道求逆序的例題,利用的便是歸併排序的原理,第一次個人排位賽沒A出來,因為還沒學歸併排序(“萬惡”的STL太方便了)


幫掛科

Time Limit: 2000/1000ms (Java/Others)

Problem Description:

冬瓜發現期末很多人都掛了線代,他決定寫個程式幫掛科的同學。在一個排列中,如果一對數的前後位置與大小
順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序。一個排列中逆序的總數就稱為這個排列的逆序數。
可是冬瓜想的頭髮都掉光了,聰明的你肯定能夠幫幫他。

Input:

輸入有多組
第1行:N,N為序列的長度(n <= 50000)
第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9)

Output:

輸出逆序數

Sample Input:

4
2
4
3
1

Sample Output:

4



附上AC程式碼:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int temp[55555];
ll ans = 0;
void unio(int l1[],int s1,int l2[],int s2)
{
    int i,j,k;
    i = j = k = 0;
    while(i < s1 && j < s2)
    {
        if(l1[i] > l2[j])
        {
            ans+=s1-i;
            temp[k++] = l2[j++];
        }
        else
            temp[k++] = l1[i++];
    }
    while(i < s1)
        temp[k++] = l1[i++];
    while(j < s2)
        temp[k++] = l2[j++];
    for(int i = 0;i < k;i++)
        l1[i] = temp[i];
}
void divi(int l[],int s)
{
    if(s > 1)
    {
        int *l1 = l;
        int s1 = s/2;
        int *l2 = l+s1;
        int s2 = s-s1;
        divi(l1,s1);
        divi(l2,s2);
        unio(l1,s1,l2,s2);
    }
}
int main()
{
    int n;
    while(cin >> n)
    {
        ans = 0;
        int a[n];
        for(int i = 0;i < n;i++)
            cin >> a[i];
        divi(a,n);
        cout << ans <<endl;
    }
    return 0;
}

相關文章