邓俊辉算法训练营习题 最小交换

最小交换
时间限制: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;
}


 

猜你喜欢

转载自blog.csdn.net/WX_1218639030/article/details/83539926