求逆序对数目(合并排序)

7-2 求逆序对数目 (30分)
注意:本问题算法的时间复杂度要求为O(nlogn), 否则得分无效

题目来源:http://poj.org/problem?id=1804 Background Raymond Babbitt drives his brother Charlie mad. Recently Raymond counted 246 toothpicks spilled all over the floor in an instant just by glancing at them. And he can even count Poker cards. Charlie would love to be able to do cool things like that, too. He wants to beat his brother in a similar task.

Problem Here’s what Charlie thinks of. Imagine you get a sequence of N numbers. The goal is to move the numbers around so that at the end the sequence is ordered. The only operation allowed is to swap two adjacent numbers. Let us try an example: Start with: 2 8 0 3 swap (2 8) 8 2 0 3 swap (2 0) 8 0 2 3 swap (2 3) 8 0 3 2 swap (8 0) 0 8 3 2 swap (8 3) 0 3 8 2 swap (8 2) 0 3 2 8 swap (3 2) 0 2 3 8 swap (3 8) 0 2 8 3 swap (8 3) 0 2 3 8

So the sequence (2 8 0 3) can be sorted with nine swaps of adjacent numbers. However, it is even possible to sort it with three such swaps: Start with: 2 8 0 3 swap (8 0) 2 0 8 3 swap (2 0) 0 2 8 3 swap (8 3) 0 2 3 8

The question is: What is the minimum number of swaps of adjacent numbers to sort a given sequence?Since Charlie does not have Raymond’s mental capabilities, he decides to cheat. Here is where you come into play. He asks you to write a computer program for him that answers the question in O(nlogn). Rest assured he will pay a very good prize for it.

输入格式:
The first line contains the length N (1 <= N <= 1000) of the sequence; The second line contains the N elements of the sequence (each element is an integer in [-1000000, 1000000]). All numbers in this line are separated by single blanks.

输出格式:
Print a single line containing the minimal number of swaps of adjacent numbers that are necessary to sort the given sequence.

输入样例:
在这里给出一组输入。例如:

6
-42 23 6 28 -100 65537
输出样例:
在这里给出相应的输出。例如:

5

百度翻译一下:
问题是查理怎么想的。假设你得到一个N个数的序列。我们的目标是移动这些数字,以便在最后的顺序是有序的。唯一允许的操作是交换两个相邻的号码。让我们尝试一个例子:从2 8 0 3交换(2 8)8 2 0 3交换(2 0)8 0 2 3交换(2 3)8 0 3 2交换(8 0)0 8 3 2交换(8 3)0 3 8 2交换(8 2)0 3 2 8 8交换(3 2)0 2 3 8 8交换(3 8 8)0 2 8 3交换(8 3 3)0 2 3 8 8 8
因此序列(2803)可以用9个相邻数字的交换来排序。然而,甚至可以用三个这样的交换来对它进行排序:首先是:2 8 0 3交换(8 0)2 0 8 3交换(2 0)0 2 8 3交换(8 3)0 2 3 8
问题是:对一个给定的序列进行排序时,相邻数字的最小交换次数是多少?由于查理没有雷蒙德的智力,他决定作弊。这就是你开始发挥作用的地方。他让你为他写一个 时间复杂度为O(nlogn) 的计算机程序。

样例
在这里插入图片描述
进行了5次相邻互换,类似冒泡排序,但是冒泡排序时间复杂度为O(n^2)
在这里插入图片描述
可以看出6的左边比6大的数有一个,-100左边有4个,最少互换次数为5

在这里插入图片描述
并且每次互换除了逆序对数目不为0的数在减小,其他为0数不变

以下为什么使用合并排序参考于bloghttps://blog.csdn.net/qq_38984851/article/details/83242429
在这里插入图片描述

#include<iostream>
using namespace std;
int num, b[10000000], a[10000000];
void merge(int a[], int b[], int l, int m, int r)
{
	int i=l, j=m+1, k=l;
	while((i<=m) && (j<=r)){
		if(a[i] <= a[j] ){               //!!!!如果左边部分一直小于右边部分,相当于直接把右边第一个接到左边最后一个,不存在逆序对,num=0 
			b[k++]=a[i++];    //左右比较,把较小那个填到数组b 
			/*
			b[k]=a[i];
			k++;
			i++;
			*/
		}
		else{
			b[k++] = a[j++];
			num += m-i+1;   //
		}
		
	}
	if(i>m){  //左边部分先于右边部分填完到数组b,把右边剩下的按原顺序填入数组b的空位 
			for(int q=j; q<=r; q++){
				b[k++] = a[q];
			}
		}
	else{   //右边部分先于左边填完 
			for(int q=i; q<=m; q++){
				b[k++]=a[q];
			}
		}
	for (int q = l; q <= r; q++)     // 中间是分成很多小步的,每次合并后都要复制回a数组 
            a[q] = b[q];
}
void mergesort(int a[], int l, int r){
	if(r>l){          //至少有2个元素 
		int i=(r+l)/2; 
		//把数组左右拆成一个个 
		mergesort(a, l, i); 
		mergesort(a, i+1, r); 
		merge(a, b, l, i, r); //合并到数组b  
	}
}
int main()
{
	num=0; 
	int n;
	cin >> n;
	for(int i=0; i<n; i++){
		cin >> a[i];
	}
	mergesort(a, 0, n-1); //r是指下标
	cout << num << endl;
	 
}

m-i+1:
在这里插入图片描述
在右边部分,对于右边来说他们的逆序对数目为0
1 2 3 6
0 0 0 0
所以只需要从中间m开始看起
对于先插入1时,i=0意思是比左边部分1小的数目为0,就是左边0个数填入了数组b
插入6的时候,i=2意思是左边有2个数填入数组b,即是左边填入的两个数不会是6的逆序对数增加
m-i+1(m+1-i)左边剩下多少个数没有填入,此时这些数(7,8)比右边即将填入数(6)要大,即逆序对数目为2
把逆序对数目累加即得答案

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值