题意:给定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; }