1.7 逆序数与归并排序[inversion pairs by merge sort]

【本文链接】

http://www.cnblogs.com/hellogiser/p/inversion-pairs-by-merge-sort.html

【题目】

编程之美1.7光影切割问题可以进一步将问题转化为求逆序数问题。

【分析】

求解逆序对问题与MergeSort类似,只需要对MergeSort稍作修改即可实现。MergeSort是采用分治法的思想,若需要排序A[p...r],则可以对半分成A[p...q]和A[q...r],然后将这有序的两部分Merge,而Merge的过程为Θ(n)的时间复杂度。根据主定率T(n)=2(Tn/2)+Θ(n),时间复杂度为T(n)=Θ(nlgn)。

同理,求整个序列中的逆序对,也可以利用分治法的思想,即

逆序对(A[p...r])= 逆序对(A[p...q])+逆序对(A[q...r])+逆序对(A[p...q], A[q...r]之间)

结合MergeSort,关键是如何在Θ(n)的时间有效的求出A[p...q], A[q...r]之间的逆序对。因为在合并排序的Merge过程中,A[p...q]和A[q...r]已经有序,假设此时已经Merge到A[i...q]和A[j...r]。考虑接下来的一步:如果A[i]<=A[j],说明A[i]比后面的序列A[j...r]中的元素都小,不存在逆序对;如果A[i]>A[j],,则说明A[j]比前面的序列A[i...q]都小,即以j结尾的逆序对的数量为前面的序列剩余序列A[i...q]中元素的数量。

Merge的过程中即可得到A[p...r], A[r...q]之间的逆序对的数量,时间复杂度亦为Θ(n), 由主定律总的时间复杂为 Θ(nlgn),这种方法要比朴素的方法 Θ(n*n)好很多。

【MergeSort】

C++ Code


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
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/6/25
*/
void merge(int *A, int p, int q, int r)
{
    //Li: p...q           Rj: q+1...r
    int n1 = q - p + 1;
    int n2 = r - (q + 1) + 1;
    int *L = new int[n1 + 1];
    int *R = new int[n2 + 1];
    // copy L and R
    for (int i = 0; i < n1; i++)
        L[i] = A[p + i];
    for (int j = 0; j < n2; j++)
        R[i] = A[q + 1 + j];
    // mark end
    L[n1] = INT_MAX;
    R[n2] = INT_MAX;
    int i = 0; // left
    int j = 0; // right
    int k = 0; // whole
    for (k = p; k <= r; k++)
    {
        if (L[i] <= R[j])
        {
            A[k] = L[i];
            i++;
        }
        else
        {
            // L[i]>R[j]
            A[k] = R[j];
            j++;
        }
    }

delete []L;
    delete []R;
}

void merge_sort(int *A, int p, int r)
{
    if (p < r)
    {
        int q = (p + r) / 2;
        merge_sort(A, p, q);
        merge_sort(A, q + 1, r);
        merge(A, p, q, r);
    }
}

void MergeSort(int *A, int n)
{
    merge_sort(A, 0, n - 1);
}

[InversionPair]

inversionPair只需要在merge函数中增加3行代码记录即可。先将inversion_pairs初始化为0,当L[i]>R[j]时,更新inversion_pairs=inversion_pairs+(n1-i),最后返回即可。同时在merge_sort中返回left_pair,right_pair和corss_pair之和即可。

C++ Code


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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/6/25
*/
int merge_pair(int *A, int p, int q, int r)
{
    //Li: p...q           Rj: q+1...r
    int n1 = q - p + 1;
    int n2 = r - (q + 1) + 1;
    int *L = new int[n1 + 1];
    int *R = new int[n2 + 1];
    // copy L and R
    for (int i = 0; i < n1; i++)
        L[i] = A[p + i];
    for (int j = 0; j < n2; j++)
        R[i] = A[q + 1 + j];
    // mark end
    L[n1] = INT_MAX;
    R[n2] = INT_MAX;
    int i = 0; // left
    int j = 0; // right
    int k = 0; // whole
    //============================
    int inversion_pairs = 0;
    //============================
    for (k = p; k <= r; k++)
    {
        if (L[i] <= R[j])
        {
            A[k] = L[i];
            i++;
        }
        else
        {
            // L[i]>R[j]
            A[k] = R[j];
            j++;
            //============================
            inversion_pairs += (n1 - i);
            //============================
        }
    }

delete []L;
    delete []R;
    //============================
    return inversion_pairs;
    //============================
}

int inversion_pair(int *A, int p, int r)
{
    if (p < r)
    {
        int q = (p + r) / 2;
        //======================================
        int left_pair = inversion_pair(A, p, q);
        int right_pair = inversion_pair(A, q + 1, r);
        int cross_pair = merge_pair(A, p, q, r);
        return left_pair + right_pair + cross_pair;
        //======================================
    }
    else
        return 0;
}

int InversionPair(int *A, int n)
{
    return inversion_pair(A, 0, n - 1);
}

【链接】

http://www.cnblogs.com/bovine/archive/2011/09/22/2185006.html

http://blog.csdn.net/zhanglei8893/article/details/6230233

【本文链接】

http://www.cnblogs.com/hellogiser/p/inversion-pairs-by-merge-sort.html

1.7 逆序数与归并排序[inversion pairs by merge sort],布布扣,bubuko.com

时间: 2024-08-08 22:07:14

1.7 逆序数与归并排序[inversion pairs by merge sort]的相关文章

求逆序数(归并排序)

求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5) 每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000) 随后的一行共有N个整

求逆序数_归并排序

求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 现在,给你一个N个元素的序列,请你判断出它的逆序数是多少. 比如 1 3 2 的逆序数就是1. 输入 第一行输入一个整数T表示测试数据的组数(1<=T<=5)每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)随后的一行共有N个整数A

逆序数 HDOJ 4911 Inversion

题目传送门 题意:可以交换两个相邻的数字顺序k次,问最后逆序对最少有多少 分析:根据逆序数的定理如果逆序数大于0,那么必定存在1<=i<n使得i和i+1交换后逆序数减1假设原逆序数为cnt,这样的话,我们就可以得到答案是max(cnt-k,0)求逆序数可以用归并的方法 代码: /************************************************ * Author :Running_Time * Created Time :2015/9/12 星期六 20:31:0

ACM_小明滚出去?(归并排序求逆序数)

小明滚出去? Time Limit: 2000/1000ms (Java/Others) Problem Description: 老师:"小明,写一个排序算法": 小明: void mysort(int a[],int n) //n为数组a的元素个数 { int i,j; for(j=0;j< n-1;j++) for(i=0;i< n-1;i++) { if(a[i] >a[i+1])//数组元素大小按升序排列 { swap(a[i],a[i+1]);//交换 }

拼图游戏中逆序数的实现的三种方式

一.定义 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.如2431中,21,43,41,31是逆序,逆序数是4. 二.计算方法 逆序数的计算方法主要有直接计算,归并和树状数组三种,下面将一一介绍. 2.1 直接计算 即根据定义用枚举的方法求逆序数.对于数列中的每一个数a[i],遍历数列中的数a[j] (其中j < i),若a[i] < a[j],则逆序数加1,这样就能统计出该数列的逆序数总和. 该方

《程序设计与算法(二)算法基础》《第五周 分治》求排列的逆序数 11

011:求排列的逆序数 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务. 对于不同的排名结果可以用逆序来评价它们之间的差异.考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序. 一个排列含有逆序的个数称为这个排

Inversion(HDU_4911) 归并排序+逆序数对

Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 3171    Accepted Submission(s): 1154 Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers f

HDU 4911 Inversion(归并排序求逆序数)

归并排序求逆序数,然后ans-k与0取一个最大值就可以了. 也可以用树状数组做,比赛的时候可能姿势不对,树状数组wa了.. Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 578    Accepted Submission(s): 249 Problem Description bobo has a seque

hdu1394--Minimum Inversion Number(线段树求逆序数,纯为练习)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10326 Accepted Submission(s): 6359 Problem Description The inversion number of a given number sequence a1, a2, ..., an is t