2299-Ultra-QuickSort-交换相邻两个数排序-求逆序对个数-合并排序

此题跟1804-Brainman相似,不过数据更强了。1840可以用暴力求解(时间为O(n^2)),而这道则不行。

 

题意:给出一组数,通过不断交换两个相邻的数,可以使这组数按非递减顺序排列。问,最小的交换次数是多少?

分析:设一组数存储在A[](初始状态 ),若A[i] > A[i+1],则交换这两个数。这一操作只会使逆序对个数减少1,对于这两个数左右两端的逆序对个数没有影响。如此,不断地交换这样的两个相邻的数,每次交换都会使逆序对个数减少1,直至A[]有序为止,此时,逆序对个数也刚好减少为0。

代码:

#include <iostream> #include <limits> using namespace std; const int MAX_SIZE = 500005; __int64 arr[MAX_SIZE]; //存输入数据 __int64 cnt; //需要的交换次数 /*合并A[p...q]和A[q+1...r]数组,初始条件为两个字数组均有序,合并后A[p...r]有序*/ void merge(__int64 A[], int p, int q, int r); /*合并排序,排序后,A[p...r]为非递减数组*/ void mergeSort(__int64 A[], int p, int r); int main() { int n; while(cin >> n, n != 0) { for(int i = 0; i < n; i++) { cin >> arr[i]; } cnt = 0; mergeSort(arr, 0, n - 1); cout << cnt << endl; } return 0; } void merge(__int64 A[], int p, int q, int r) { int n1 = q - p + 1; //字数组A[p...q]长度 int n2 = r - q; //字数组A[q+1...r]长度 __int64 L[n1 + 1]; //辅助数组 __int64 R[n2 + 1]; //辅助数组 /*初始化*/ for(int i = 0; i < n1; i++) L[i] = A[p + i]; for(int i = 0; i < n2; i++) R[i] = A[q + 1 + i]; L[n1] = numeric_limits<__int64>::max(); //末端置最大值,作哨兵 R[n2] = numeric_limits<__int64>::max(); //同上 /*以下循环将L,R字数组合并到A数组*/ int i = 0, j = 0; for(int k = p; k <= r; k++) { if(L[i] <= R[j]) { A[k] = L[i]; i++; } else { A[k] = R[j]; j++; cnt += n1 - i; //求逆序对个数——关键一步! } } } void mergeSort(__int64 A[], int p, int r) { if(p >= r) return ; //结束条件 /*分解*/ int q = (p + r) / 2; //取“中间”数作为分界点 /*解决*/ mergeSort(A, p, q); //递归排序 mergeSort(A, q + 1, r); //同上 /*合并*/ merge(A, p, q, r); }

你可能感兴趣的:(存储,merge,n2)