HDU-1394-Minimum Inversion Number

HDU-1394-Minimum Inversion Number

http://acm.hdu.edu.cn/showproblem.php?pid=1394

题意是给出n个数,求其逆序数,并每次将第一个数移至最后,再求其逆序数,求这n个排列中逆序数最小的一个

逆序数的简单定义:The inversion number of a givennumber sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i< j and ai > aj.

假设已求得一个排列的逆序数为sum,并且数组为a[n],现把第一个数移至末尾,因为0至n-1个数连续,比a[0]大的数将变成逆序,比a[0]小的数将不构成逆序,所以现在的逆序数为sum+=(比a[0]大的数—比a[0]小的数)

即sum+=(n-1-a[0]-a[0])   即sum+=(n-1-2*a[0])

此时求原始排列的逆序数可用暴力的方法,即每个数都和前面的数比较

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
	int n,sum,i,j,ans;
	int a[5005];
	while(scanf("%d",&n)!=EOF)
	{
		for(i=0;i<n;i++)
		scanf("%d",&a[i]);
		sum=0;
		for(i=0;i<n;i++)
		for(j=0;j<i;j++)
		if(a[j]>a[i])
		sum++;
		ans=sum;
		for(i=0;i<n;i++)
		{
			sum+=(n-1-2*a[i]);
			if(sum<ans)
			ans=sum;
		}
		printf("%d\n",ans);
	}
	return 0;
}

暴力的方法在求原始排列的逆序数时比较耗时,此题也可用线段树来做

1 3 6 9 0 8 5 7 4 2

依次插入,插入1时,(1,n-1]中出现的有v1=0

插入3时,(3,n-1]中出现的有v2=0

...

插入0时,(0,n-1]中出现的有v5=4

...

将v1至v10叠加即可

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 5005
int a[N];
struct cam
{
	int x; //起点
	int y; //终点
	int val; 
}list[N*4];
void build(int k,int x,int y)  //建树
{
	int mid;
	list[k].x=x;
	list[k].y=y;
	list[k].val=0;
	if(list[k].x==list[k].y)
	return;
	mid=(x+y)/2;
	build(k<<1,x,mid);
	build(k<<1|1,mid+1,y);
}
int find(int k,int x,int y)  //(x,y]中比x大且出现的数
{
	int mid;
	if(list[k].x==x&&list[k].y==y)
	return list[k].val;
    mid=(list[k].x+list[k].y)/2;
	if(x>mid)
	return find(k<<1|1,x,y);
	else if(y<=mid)
	return find(k<<1,x,y);
	else
	return find(k<<1,x,mid)+find(k<<1|1,mid+1,y);
}
void update(int x,int k)  //更新所有包含x的区间的val值
{
	int mid;
    list[k].val++;
    if(list[k].x==list[k].y)
	return;
	mid=(list[k].x+list[k].y)/2;
	if(x<=mid)
	update(x,k<<1);
	else
	update(x,k<<1|1);
}
int main()
{
    int i,n,sum,ans;
	while(scanf("%d",&n)!=EOF)
	{
		build(1,0,n-1);
		sum=0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			sum+=find(1,a[i],n-1);
			update(a[i],1);
		}
		ans=sum;
		for(i=0;i<n;i++)
		{
			sum+=(n-1-2*a[i]);
			if(sum<ans)
			ans=sum;
		}
		printf("%d\n",ans);
	}
	return 0;
}




posted on 2012-07-21 10:05  java课程设计例子  阅读(161)  评论(0编辑  收藏  举报