题意:给定一组无序序列,每次只能交换相邻的两个元素,求最少交换几次才能使序列有序。
思路:冒泡可以做,但是会超时,所以必须想其它办法,这里使用归并排序,在合并两个子序列时计算需要付出的逆序数,最后逆序数的总和即为最少交换次数。
所谓逆序数就是逆序排列的个数,比如一组数为:2,4,3,1,则逆序数为:4。(这里规定升序是标准序)
对于2来说,21逆序;
对于4来说,43、41逆序;
对于3来说,31逆序;
对于1来说,无逆序;
所以逆序数为1+2+1+0=4。
code:
#include <iostream>
#include <fstream>
using namespace std;
__int64 result;//逆序数
const int inf = 1000000000; //10E
void merge_array(int data[], int left, int mid, int right)
{
int len_L = mid - left + 1;
int len_R = right - mid;
int* a = new int[len_L + 2];
int* b = new int[len_R + 2];
int i, j;
for (i = 1; i <= len_L; i++)
a[i] = data[left + i - 1];
a[len_L + 1] = inf; //设置无穷上界,避免比较大小时越界
for (j = 1; j <= len_R; j++)
b[j] = data[mid + j];
b[len_R + 1] = inf; //设置无穷上界,避免比较大小时越界
i = j = 1;
for (int k = left; k <= right; k++)
{
if (a[i] <= b[j])
data[k] = a[i++];
else
{
data[k] = b[j++];
result += len_L - i + 1; //计算逆序数
}
}
delete a;
delete b;
return;
}
void mergesort(int data[],int left,int right)
{
if (left < right)
{
int mid = (left + right) / 2;
mergesort(data, left, mid);
mergesort(data, mid + 1, right);
merge_array(data, left, mid, right);
}
return;
}
int main()
{
//fstream in("input.txt");
int num, i;
while (cin >> num)
{
if (num == 0)
break;
//input
int* data = new int[num+1];
for (i = 1; i <= num; i++)
{
cin >> data[i];
}
//handle
result = 0;
mergesort(data,1,num);
//output
printf("%I64d\n", result);
delete data;
}
//system("pause");
return 0;
}