归并排序,采用的是分治的思想,例如:
0 4 2 1 3
这个数组,先分成两部分
0 4 和 2 1 3
再分成两部分
0 和 4 和 2 和 13
最后则
0 和 4 和 2 和 1 和 3
然后, 建立新数组
0 和 4,0小于4
则新数组为0 4
同理可得 1 3
则可得0 4 和 2 和 1 3
再建立新数组,对比0 4 和 2
显然,0 小于2,新数组0
再对比4 和2,2 小于4,则新数组0 2
最后剩下个4,则新数组0 2 4
再对比0 2 4 和 1 3
原理同上,最后得到
0 1 2 3 4
给一道求逆序的例题,利用的便是归并排序的原理,第一次个人排位赛没A出来,因为还没学归并排序(“万恶”的STL太方便了)
帮挂科
Time Limit: 2000/1000ms (Java/Others)
Problem Description:
冬瓜发现期末很多人都挂了线代,他决定写个程序帮挂科的同学。在一个排列中,如果一对数的前后位置与大小 顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。 可是冬瓜想的头发都掉光了,聪明的你肯定能够帮帮他。
Input:
输入有多组 第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9)
Output:
输出逆序数
Sample Input:
4 2 4 3 1
Sample Output:
4
附上AC代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int temp[55555];
ll ans = 0;
void unio(int l1[],int s1,int l2[],int s2)
{
int i,j,k;
i = j = k = 0;
while(i < s1 && j < s2)
{
if(l1[i] > l2[j])
{
ans+=s1-i;
temp[k++] = l2[j++];
}
else
temp[k++] = l1[i++];
}
while(i < s1)
temp[k++] = l1[i++];
while(j < s2)
temp[k++] = l2[j++];
for(int i = 0;i < k;i++)
l1[i] = temp[i];
}
void divi(int l[],int s)
{
if(s > 1)
{
int *l1 = l;
int s1 = s/2;
int *l2 = l+s1;
int s2 = s-s1;
divi(l1,s1);
divi(l2,s2);
unio(l1,s1,l2,s2);
}
}
int main()
{
int n;
while(cin >> n)
{
ans = 0;
int a[n];
for(int i = 0;i < n;i++)
cin >> a[i];
divi(a,n);
cout << ans <<endl;
}
return 0;
}