【POJ1804】Brainman 【求逆序数】

题意:

给你一串序列,每次只能交换序列中相邻的数字,问最少需要操作几次能将序列变成有序的。

思路:

本题从逆序对出发思考,可以发现,交换一对相邻数字最多只能减少一对逆序对。

因此不难想到,本题的最少操作数就是所有逆序对个数。

此类问题还有很多,比如取区间中的一段连续数字插入数列中任意位置,需要多少次可以让数列变成有序数列。

此时就需要考虑每一次插入,最多可以改变几个数字的后继,和本题也是一样的思考方式。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 1500;

int a[N],cnt,tmp[N];

void Merge(int l,int mid,int r)
{
	//合并a[l-mid]与a[mid+1-r]
	int i = l, j = mid+1;
	rep(k,l,r)
		if(j > r || (i <= mid && a[i] <= a[j])) tmp[k] = a[i++];	//此处是<还是<=,取决于题意,即5,5是否算一对逆序对
		else tmp[k] = a[j++], cnt += mid-i+1;
	rep(k,l,r) a[k] = tmp[k];
}

void Mergesort(int l,int r)
{
	if(l < r)
	{
		int mid = (l+r)>>1;
		Mergesort(l,mid);
		Mergesort(mid+1,r);
		Merge(l,mid,r);
	}
}

int main()
{
	int T;
	scanf("%d",&T);
	rep(cas,1,T)
	{
		cnt = 0;
		int n;
		scanf("%d",&n);
		rep(i,1,n)
			scanf("%d",&a[i]);
		Mergesort(1,n);
		printf("Scenario #%d:\n%d\n\n",cas,cnt);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/81736961
今日推荐