經典問題之最少交換次數
阿新 • • 發佈:2019-01-30
題目簡述:
此類題目一般概括為:通過交換相鄰數來完成排序所需要的最少交換次數。
分析:
顯然簡單的氣泡排序就是基於這種思想,但是O(n^2)的效率常常無法滿足題目要求,我們只能另尋它路。
還是模擬原始做法:
4 8 2 7 5 6 1 3
1 4 8 2 7 5 6 3------>6次
1 2 4 8 7 5 6 3------>2次
1 2 3 4 8 7 5 6------>5次
1 2 3 4 5 8 7 6------>2次
1 2 3 4 5 6 8 7------>2次
1 2 3 4 5 6 7 8------>1次
統計18次
在模擬過程中,我們發現每次都是找到一個最小的然後移到最前面,但是除了這個最小的,其他數的相對次序並沒有改變,所以我們可以將原始做法換一種表述方式:
找到最小的,統計它前面有多少個數比它小,然後加入結果,將這個最小的刪去。
這時我們就發現,其實原題就是求數列的逆序對的個數!
樹狀陣列。線段樹。歸併。
參考程式:
#include<cstdio> #include<algorithm> using namespace std; const int maxn=210000; int n,a[maxn],b[maxn]; int bit(int x){ return x&(-x); } void add(int x){ while (x<=30){ b[x]++; x+=bit(x); } } int query(int x){ int tt=0; while (x>0){ tt+=b[x]; x-=bit(x); } return tt; } int main(){ freopen("swapping.in","r",stdin); freopen("swapping.out","w",stdout); char cmd; while (scanf("%c",&cmd)==1) a[++n]=cmd-'A'+1; int ans=0; for (int i=1;i<=n;i++){ add(a[i]); ans+=i-query(a[i]); } printf("%d",ans); return 0; }