1. 程式人生 > >鄧俊輝演算法訓練營習題 最小交換

鄧俊輝演算法訓練營習題 最小交換

最小交換 時間限制:1 sec

空間限制:256 MB

問題描述 給定一個 1 到 n 的排列(即一個序列,其中 [1,n] 之間的正整數每個都出現了恰好 1 次)。

你可以花 1 元錢交換兩個相鄰的數。

現在,你希望把它們升序排序。求你完成這個目標最少需要花費多少元錢。

輸入格式 第一行一個整數 n,表示排列長度。

接下來一行 n 個用空格隔開的正整數,描述這個排列。

輸出格式 輸出一行一個非負整數,表示完成目標最少需要花多少元錢。

樣例輸入 3 3 2 1 樣例輸出 3 樣例解釋 你可以:

花 1 元交換 1,2,序列變成 3 1 2。

花 1 元交換 1,3,序列變成 1 3 2。

花 1 元交換 2,3,序列變成 1 2 3。

總共需要花 3 元。

可以證明不存在更優的解。

資料範圍 對於 20% 的資料,保證 n<=7。

對於 60% 的資料,保證 n<=1,000。

對於 100% 的資料,保證 n<=200,000。

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

int ans = 0;//計數
vector<int> line;//各個元素
vector<int> NewLine;//儲存新排列好的序列
int merger(int l,int r){
    if(l >= r) //l == r --> 一個元素 無法歸併
        return 0;

    int mid = r >> 1;//向左移1位 即利用二進位制的性質 二分
    merger(l,mid);//歸併前驅序列
    merger(mid + 1,r);//歸併後驅序列

    int q = l,p = mid + 1;
    //p > r代表右半部分已經歸併完成
    //q <= mid && line[q] < line[p] -> 前驅序列的元素更小
    if(p > r || q <= mid && line[q] < line[p])
        NewLine.push_back(line[q++]);//q++ ->將q移到下一位
    else{
        NewLine.push_back(line[p++]);
        ans += mid - q + 1;//參考氣泡排序(已證明最少的交換次數即冒泡交換次數)
    }
    return ans;//返回交換次數
}
int getAnswer(int n){
    int l = 0,r = n - 1;
    return merger(l,r);
}
int main(int argc, char const *argv[]) {
    //n 代表元素數目
    int n;
    scanf("%d",&n);

    for(int i = 0;i < n;i++){
        int a;
        scanf("%d",&a);
        line.push_back(a);
    }
    printf("%d",getAnswer(n));
    return 0;
}