Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
最小交换次数就是这个序列的逆序数,线代里有过证明,用归并排序就可以了/* 归并排序,求逆序数 */ #include<cstdio> #pragma warning (disable:4996) using namespace std; long long count = 0; //逆序数 int arr[500010]; int temp[500010]; //辅助数组(暂时存放排序结果) void merge(int arr[], int start, int medium, int end) //start为第一段子序列的起点,medium为第一段的终点,medium+1为第二段的起点,end为第二段的终点,包括头尾 { int i = start, j = medium+1; //i,j分别为两段的头指针,i从第一段的起点开始,j从第二段的起点开始 int k = 0; while (i <= medium && j <= end) //将两段子序列中的最短一段所有数字都比较完毕 { if (arr[i] < arr[j]) //逐个将两个子序列中最小的数存放在辅助数组中 { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; count += medium - i + 1; //逆序数核心!!!第一段尾减去第一段头,即为第二段插入元素当前的逆序数 } } while (i <= medium) //说明第一段元素没有全部比较完,将剩下元素全部放入辅助数组 { temp[k++] = arr[i++]; } while (j <= end) //说明第二段元素没有全部比较完,将剩下元素全部放入辅助数组 { temp[k++] = arr[j++]; } for (int m = 0; m < k; m++) //将原数组arr中顺序更新 { arr[start++] = temp[m]; //注意数组从start开始更新,不是从0更新!! } } void mergeSort(int arr[],int start,int end) { if (start == end) return; int medium = (start + end) / 2; mergeSort(arr,start,medium); //递归调用自己 mergeSort(arr, medium + 1, end); merge(arr, start, medium, end); } int main() { //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); int n; while (scanf("%d", &n) != EOF && n != 0) { count = 0; for (int i = 0; i < n; i++) scanf("%d", &arr[i]); mergeSort(arr, 0, n - 1); printf("%lld\n", count); } return 0; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator