【C语言算法】求逆序对数目(C语言+归并排序)

题目描述

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.

翻译:

背景Raymond Babbitt把他的兄弟Charlie逼疯了。最近,Raymond只看了一眼,就数出246根牙签瞬间洒了一地。他甚至会数扑克。查理也很想做那种很酷的事情。他想在类似的任务中打败他的兄弟。


问题这是查理的想法。想象一下,你得到一个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交换(3 2)
0 2 3 8交换(3 8)
0 2 8 3交换(8 3)
0 2 3 8


因此,序列(2 8 0 3)可以通过九个相邻数字的交换进行排序。但是,甚至可以用三种这样的交换对其进行排序:

从:

2 8 0 3交换(8 0)

2 0 8 3交换(2 0)

0 2 8 3互换(8 3)

0 2 3 8

开始


问题是:

对给定序列进行排序时,相邻数字的最小交换次数是多少?由于查理没有雷蒙德的智力,他决定作弊。这就是你发挥作用的地方。他让你为他写一个计算机程序,回答O(nlogn)中的问题。请放心,他会为此支付很高的奖金。

大概意思:

 求相邻数之间最少的交换次数。交换之后是符合递增顺序的(小->大)

输入格式

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.

翻译:

第一行包含序列的长度N(1<=N<=1000)第二行包含序列的N个元素(每个元素都是[-1000000,1000000]中的整数)。这一行中的所有数字都用一个空格隔开。

输出格式

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

 代码示例:

#include <stdio.h>
#include <string.h>
int sum=0;
void merge(int arr[],int L,int M,int R)//治
{
	
	//从中间对半分开,求左右数组长度和数组
	int L_size=M-L;
	int R_size=R-M+1;
	int left[L_size];
	int right[R_size];
	
	for(int i=L;i<M;i++)
	{
		left[i-L]=arr[i];
	}
	for(int i=M;i<=R;i++)
	{
		right[i-M]=arr[i];
	}
	
	//左右数组将小的先放进原先数组,以此类推
	int i = 0,j = 0,k = L;
	while(i<L_size&&j<R_size)
	{
		if(left[i]<right[j])
		{
			arr[k]=left[i];
			i++;
			k++;
		}
		else
		{
			arr[k]=right[j];
			j++;
			k++;
            //在这里,我们增加sum,因为left数组中的元素比right数组中的元素大,
            //符合逆序对定义(左边的数比右边的数大)
			sum += L_size - i;
		}
	}
	//未进行比较的(当一个数组的元素全部已放入,就无需比剩下一个数组的元素了,因为数组原先已经排好顺序)直接放入
	while(i<L_size)
	{
		arr[k]=left[i];
		i++;
		k++;
	}
	while(j<R_size)
	{
		arr[k]=right[j];
		j++;
		k++;
	}
}

void mergesort(int arr[],int L,int R)//归并排序,分
{
	if(L==R)
	{
		return;
	}
	else
	{
		int M=(L+R)/2+1;
		mergesort(arr,L,M-1);
		mergesort(arr,M,R);
		merge(arr,L,M,R);
	}
}
int main()
{
	int n;
	scanf("%d",&n);
	int arr[10000]={0};
	for(int i=0;i<n;i++)
	{
		scanf("%d",&arr[i]);
	}
	int L=0;
	
	mergesort(arr,L,n-1);
	
	printf("%d",sum);
	
	return 0;
}

问题拓展解释:

为什么sum的值为sum += L_size - i;?

答:

在归并排序中计算逆序对时,当我们从right数组取出一个元素并放入到arr数组的当前位置k时,说明left数组中从当前位置i到末尾的所有元素都比这个从right数组取出的元素大。因此,这些left数组中的元素与刚放入的right数组中的元素都会形成逆序对。
 

具体来说,对于left数组中当前位置i之后的每一个元素,它与right数组中当前已放入arr数组的元素都形成了一个逆序对。因为right数组中的这个元素在合并后的arr数组中的位置比left数组中这些元素的位置要靠前,而它们的值又比left数组中的这些元素小。

假设left数组的大小是L_size,当前已经处理了i个元素(即left数组中前i个元素已经正确地放入了arr数组),那么left数组中还未处理的元素数量就是L_size - i。这些元素都将与刚刚从right数组取出的元素形成逆序对。

因此,每当我们从right数组取出一个元素并放入arr数组时,我们就需要增加sum的值,增加的数量正好是left数组中还未处理的元素数量,即L_size - i

NO.45

有问题敬请斧正!感谢您的支持。

<C语言算法> 

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木鳶戾天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值