题意:给定n个数,问通过交换相邻元素的方法将其排序最少需要交换多少个相邻元素。
思路:1、本质上就是求序列的逆序数个数。首先想到的方法当然是基于分治的归并排序外加统计逆序。
2、树状数组做法,先对数组排序。然后扫原数组,每个数在排序好的数组中查找下标,在它前面比它大的个数就是当前元素的逆序对,然后将其删除。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 500005
int s[N],t[N],n;
__int64 merge_sort(int a,int b){
int i,j,c;
__int64 res=0;
if(a == b)
return 0;
c = ((a+b)>>1)+1;
res += merge_sort(a,c-1);//分别统计两段数组内部的逆序个数
res += merge_sort(c,b);
for(i = a;i<=b;i++)
t[i] = s[i];
for(i = a,j = c;i<c&&j<=b;){//归并排序的过程,外加统计两段数组之间的逆序数
if(t[i] <= t[j])
s[i+j-c] = t[i++];
else{
s[i+j-c] = t[j++];
res += c-i;
}
}
while(i<c)
s[i+j-c] = t[i++];
while(j<=b)
s[i+j-c] = t[j++];
return res;
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d",&n) && n){
int i;
for(i = 0;i<n;i++)
scanf("%d",&s[i]);
printf("%I64d\n",merge_sort(0,n-1));
}
return 0;
}
树状数组:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
#define N 500005
using namespace std;
int s[N],t[N],tree[N];
int n;
int lowbit(int x){
return x&(-x);
}
void add(int i,int x){
int j;
for(j = i;j<=n;j+=lowbit(j))
tree[j] += x;
}
int sum(int x){
int i,res=0;
for(i = x;i>0;i-=lowbit(i))
res += tree[i];
return res;
}
int find(int x){
int low,high,mid;
low = 1;
high = n;
while(low <= high){
mid = (low+high)/2;
if(x == t[mid])
return mid;
else if(x < t[mid])
high = mid-1;
else
low = mid+1;
}
return 0;
}
int main(){
while(scanf("%d",&n) && n){
int i,j;
long long res = 0;
memset(tree,0,sizeof(tree));
for(i = 1;i<=n;i++)//初始化树状数组
add(i,1);
for(i = 1;i<=n;i++){
scanf("%d",&s[i]);
t[i] = s[i];
}
sort(t+1,t+n+1);
for(i = 1;i<=n;i++){//每次在排好序的数组里查找下标,在它前面比它大的数量就是所求
j = find(s[i]);
res += sum(j-1);
add(j,-1);
}
printf("%lld\n",res);
}
}
2188也是求逆序数,只不过给定两个序列,求这两个序列的逆序对。
做法只是需要先将其中的一个序列更名到1-n,然后就是纯粹的求逆序对。这里用树状数组求的,而且可以不用二分。先求出数组中元素对应的下标,然后从数组中最小的元素开始在树状数组中查找。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 0x3fffffff
#define clr(s,t) memset(s,t,sizeof(s))
#define N 1005
int n;
int s[N],t[N],flag[N],tree[N];
struct node{
int a,b;
}p[N];
int cmp(node x,node y){
return x.b < y.b;
}
int lowbit(int x){
return x&(-x);
}
void add(int i,int x){
for(int j = i;j<=n;j+=lowbit(j))
tree[j] += x;
}
int sum(int i){
int j,res= 0;
for(j = i;j>=1;j-=lowbit(j))
res += tree[j];
return res;
}
int main(){
int i,res=0;
scanf("%d",&n);
clr(tree, 0);
for(i = 1;i<=n;i++){
scanf("%d %d",&s[i],&t[i]);
flag[s[i]] = p[i].a = i;
}
for(i = 1;i<=n;i++)
p[i].b = flag[t[i]];
sort(p+1,p+1+n,cmp);
for(i = 1;i<=n;i++){
res += sum(n)-sum(p[i].a);
add(p[i].a,1);
}
printf("%d\n",res);
return 0;
}