1. 程式人生 > >【演算法競賽進階指南】逆序對POJ2299Ultra-QuickSort

【演算法競賽進階指南】逆序對POJ2299Ultra-QuickSort

求逆序對需要用到的演算法是歸併排序,在排序的同時進行計算逆序對,改題目求冒泡的次數,實際上就是最少逆序對的個數,最小個數的話利用歸併排序中進行歸併的時候,如果左半邊有大於右半邊最小的值,能麼從該位置到左邊最後一個都與右半邊第一個構成逆序對,逆序對個數加上左邊個數,歸併排序利用遞迴,所以在本次排序的時候,左右半邊都已經有序了

注意歸併排序的演算法,需要再加強一下學習

void mergesort(int l,int r){
    int mid=(l+r)>>1;
    int i=l,j=mid+1;
    for(int k=l;k<=r;k++){
        if(j>r || (i<=mid && a[i]<a[j])) b[k]=a[i++];
        else b[k]=a[j++];
    }
    for(int k=l;k<=r;k++) a[k]=b[k];
}
void merge(int l,int r){
    int mid=(l+r)>>1;
    if(l<r){
        merge(l,mid);
        merge(mid+1,r);
        mergesort(l,r);
    }
}

上面是歸併排序的核心演算法,而下面是題目的程式碼

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
long long a[500005],b[500005],cnt;

void mergesort(int l,int mid,int r){
    int i=l,j=mid+1;
    for(int k=l;k<=r;k++){
        if(j>r || (i<=mid && a[i]<a[j])) b[k]=a[i++];
        else b[k]=a[j++],cnt+=mid-i+1;
    }
    for(int k=l;k<=r;k++) a[k]=b[k];
    return;
}

void merge(int l,int r){
    int mid=(l+r)>>1;
    if(l<r){
        merge(l,mid);
        merge(mid+1,r);
        mergesort(l,mid,r);
    }
    return;
}

int main(){
    int n;
    while(cin>>n&&n!=0){
        cnt=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        merge(1,n);
        cout<<cnt<<"\n";
    }
    return 0;
}