背景
雷蒙德·巴比特把他弟弟查理逼疯了。最近,雷蒙德只扫了一眼,就数出246根牙签在瞬间撒了一地。他甚至会数扑克牌。查理也很想做这样酷的事情。他想在类似的任务中击败他的兄弟。
问题
以下是查理的想法。假设你有一个N个数的序列。这样做的目的是移动数字,使序列的最后是有序的。唯一允许的操作是交换两个相邻的数。让我们举个例子:
从2803开始......
所以这个数列(2 8 0 3)可以用9次交换相邻数来排序。然而,它甚至可以用三种这样的交换来排序:
......
问题是:对给定序列进行相邻数交换的最小次数是多少?由于查理没有雷蒙德那样的智力,他决定作弊。这就是你发挥作用的地方。他让你为他写一个计算机程序,用O(nlogn)来回答这个问题。放心吧,他会为此出个好价钱的。
Input formats:
第一行包含序列的长度N (1 <= N <= 1000);第二行包含序列的N个元素(每个元素都是[-1000000,1000000]中的整数)。这一行中的所有数字都用空格隔开。
The output format:
打印一行,其中包含对给定序列排序所必需的相邻数交换的最小次数。
输入样例:
在这里给出一组输入。例如:
6
-42 23 6 28 -100 65537
输出样例:
在这里给出相应的输出。例如:
5
代码:
#include<iostream>
using namespace std;
int num;
void merge(int a[], int b[], int l, int m, int r)
{
int i=l, j=m+1, k=l;
while((i<=m) && (j<=r)){
if(a[i] <= a[j] ){ //!!!!如果左边部分一直小于右边部分,相当于直接把右边第一个接到左边最后一个,不存在逆序对,num=0
b[k++] = a[i++]; //左右比较,把较小那个填到数组b
}else{
b[k++] = a[j++];
num += m-i+1; //
}
}
if(i>m){ //左边部分先于右边部分填完到数组b,把右边剩下的按原顺序填入数组b的空位
for(int q=j; q<=r; q++){
b[k++] = a[q];
}
}else{ //右边部分先于左边填完
for(int q=i; q<=m; q++){
b[k++]=a[q];
}
}
for (int q = l; q <= r; q++) // 中间是分成很多小步的,每次合并后都要复制回a数组
a[q] = b[q];
}
void mergesort(int a[],int b[], int l, int r){
if(r>l){ //至少有2个元素
int i=(r+l)/2;
//把数组左右拆成一个个
mergesort(a, b, l, i);
mergesort(a, b, i+1, r);
merge(a, b, l, i, r); //合并到数组b
}
}
int main()
{
num=0;
int n;
cin >> n;
int a[n], b[n];
for(int i=0; i<n; i++)
cin >> a[i];
mergesort(a, b, 0, n); //r是指下标
cout << num << endl;
}
// https://blog.csdn.net/weixin_45689999/article/details/110659992