归并排序(合并排序)(逆序对)

Description

在这个问题中,你需要分析一个对n个不同数排序的算法。该算法主要通过交换相邻数直到序列有序(升序)。比如:对输入序列

9 1 0 5 4

经过一系列交换后变成有序序列

0 1 4 5 9
你的任务是计算将序列变成有序最少需要经过多少次交换。

Input

输入包含多组测试数据。每组第一个是整数n<500,000,表示输入序列的长度,接下来是n行,每行有一个整数a[i](0≤a[i]≤999,999,999)。当n=0时表示结束。

Output

对每一组输入,输出该序列变成有序所需要交换的最少的次数。

Sample Input

5
9
1
0
5
4
3
1
2
3
0

Sample Output

6
0

Hint

选做

合并排序

Waterloo local 2005.02.05

代码:

+ ?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

#include<cstdio>

#include<cmath>

#include<cstring>

#include<iostream>

#include<algorithm>

using
namespace std;

long
long a[500001],b[500001];

long
long cnt;

void
merge_bing(long
long frist,long
long mid,long
long last)

{

    long
long midd=mid+1;

    long
long d=0;

    long
long f=frist;

    while(frist<=mid&&midd<=last)

    {

        if
(a[frist]<=a[midd])

            b[d++]=a[frist++];

        else

        {

            cnt+=mid-frist+1;

            b[d++]=a[midd++];

        }

    }

    while(frist<=mid)

        b[d++]=a[frist++];

    while(midd<=last)

        b[d++]=a[midd++];

    for(long
long i=0;i<d;i++)

        a[f++]=b[i];

}

void
mergesort(long
long frist,long
long last)

{

    long
long mid=0;

    if
(frist<last)

    {

        mid=(frist+last)/2;

        mergesort(frist,mid);

        mergesort(mid+1,last);

        merge_bing(frist,mid,last);

    }

}

int
main()

{

    int
n;

    while(scanf("%d",&n)&&n)

    {

        int
i,j;

        for(i=0;i<n;i++)

            scanf("%lld",&a[i]);

        cnt=0;

        mergesort(0,n-1);

        printf("%lld\n",cnt);

    }

    return
0;

}

  

时间: 2024-11-08 07:44:57

归并排序(合并排序)(逆序对)的相关文章

[PHP] 算法-数组归并排序并计算逆序对的个数的PHP实现

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 1.数组归并排序 2.归并排序比较左右两个堆数组中的元素大小时,进行计数,倒着比较,因为左堆倒第一如果比右堆倒第一大,那么就比右堆的所有都大 mergeSort if left<right mid=[(p+r)/2] mergeSort(arr,left,mid,temp) mergeSort(

P1136 归并排序,求逆序对个数

这道题从看到它开始到做出来,已经过了快两周[因为第一次思路完全跑偏写的是暴力模拟想水过]: 题意是这样的:  jzabc除了对多米诺骨牌感兴趣外,对赛车也很感兴趣.上个周末他观看了一场赛车比赛.他总是能想出许多稀奇的问题.某一时刻,他看到有n辆车(总是匀速行驶)在同一直线上,并且处在一个无限长度的直道上,而且n辆车有严格的先后之分.他通过特殊的器材测出了每一辆车的速度.那么问题出现了,如果有两辆车A车和B车,A车在B车的后面,并且A车的速度比B车的快,那么经过一段时间后,A车一定会超过B车.我们

归并排序 及拓展—逆序对

归并排序 时间复杂度 归并排序时间复杂度为O(NlogN) 似乎和快速排序差不多,但在有些特定的场合下,归并排序却能起到快速排序达不到的效果(如一年的联赛题,瑞士轮) 思路及实现 归并排序分为两个步骤,分.合: 分 的过程我们用二分的思路实现: 合 的过程时间复杂度可达到O(n); 分: 进行分治: 假设当前处理的区间为l~r; 实现: 过程定义:void merge_sort(int l,int r) merge_sort(l,l+r>>1); merge_sort(l+r>>1

ACM:归并排序,以及利用归并排序思想求解逆序对数!

(一)归并排序 分析: (1)划分问题:把序列分成元素个数尽量相等的两半. (2)递归求解:把两半元素分别排序. (3)合并问题:把两个有序表合并成一个.(每次只需要把两个序列的最小元素加以比较,删除其中的较小元素并加入合并后的新表) #include <iostream> using namespace std; const int MAXN = 1000; int A[MAXN], T[MAXN]; void merge_sort(int *A, int x, int y, int *T)

求逆序对 36

? ? 引言 ? ? 一开始接触到这题还觉得挺有意思的,但后来发现其深层次的含义就是一个归并排序,只是在归并排序的过程中做了一点小动作而已,这也再次证明了很多东西都是万变不离其宗的 ? ? 本文首先讲了一下归并排序的过程,用了自己比较喜欢的简洁的方式,然后对比归并排序与求逆序对之间的关系,发现需要稍微修改一下合并两个已排序数组的方法,要从两个数组的最后的数开始 ? ? 最后考虑到如果求逆序对的字符是固定数目的话,比如4个,详情可以参考后面的,那么时间复杂度不用归并排序的nlogn了,如果我们可以

树状数组求逆序对

给定n个数,要求这些数构成的逆序对的个数.除了用归并排序来求逆序对个数,还可以使用树状数组来求解.树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了.把所有的加起来就是总的逆序对数.题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000.如果采用上面的思想,必然会导致空间的巨大浪费,而且由

36 - 求数组中的逆序对

题目描述:http://ac.jobdu.com/problem.php?pid=1348 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 如输入{7,5,6,4}中,共存在5个逆序对:(7,6) (7,5) (7,4) (6,4) (5,4) 解析: 直观思路是: 从第一个数字开始,让它和后面的每个数字比较,找出所有逆序对.时间复杂度O(n2) 改进思路: 只要让一个数字和其他的每个数字比较,那么时间就是O(n2).

【剑指offer】面试题36:数组中的逆序对

题目: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 思路: 归并排序的合并过程.主要是考虑合并两个有序序列时,计算逆序对数. 对于两个升序序列,设置两个下标:两个有序序列的末尾.每次比较两个末尾值,如果前末尾大于后末尾值,则有”后序列当前长度“个逆序对:否则不构成逆序对.然后把较大值拷贝到辅助数组的末尾,即最终要将两个有序序列合并到辅助数组并有序. 这样,每次在合并前,先递归地处理左半段.右半段,则左.右半段有序,

分治法 求 逆序对数 的个数 时间复杂度为O(n*logn)

思路: 分治法 归并排序的过程中,有一步是从左右两个数组中,每次都取出小的那个元素放到tmp[]数组中 右边的数组其实就是原数组中位于右侧的元素.当不取左侧的元素而取右侧的元素时,说明左侧剩下的元素均比右侧的第一个元素大,即均能构成一个逆序对.假设现在左侧剩余n个元素,则逆序对数+n. 另外,如果当所有右侧的元素都取完,但是左侧仍然有元素剩余时,左侧剩余的元素已经在之前的运算中加到了逆序对中,不需要再添加一次 下面给出 归并排序 和 求逆序对数 两份代码: code1: 归并排序 #includ

HDU 4911 Inversion(归并求逆序对)

HDU 4911 Inversion 题目链接 题意:给定一个数组,可以相邻交换最多k次,问交换后,逆序对为多少 思路:先利用归并排序求出逆序对,然后再减去k就是答案 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 100005; int n, num[N], save[N], sn; void init() { for