zoukankan      html  css  js  c++  java
  • 《程序设计与算法(二)算法基础》《第五周 分治》求排列的逆序数 11

    011:求排列的逆序数

    总时间限制: 
    1000ms
     
    内存限制: 
    65536kB
    描述

    在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务。

    对于不同的排名结果可以用逆序来评价它们之间的差异。考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。

    一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

    现给定1,2,…,n的一个排列,求它的逆序数。


    输入
    第一行是一个整数n,表示该排列有n个数(n <= 100000)。
    第二行是n个不同的正整数,之间以空格隔开,表示该排列。
    输出
    输出该排列的逆序数。
    样例输入
    6
    2 6 3 4 5 1
    样例输出
    8
    提示
    1. 利用二分归并排序算法(分治);
    2. 注意结果可能超过int的范围,需要用long long存储。
    /*
    http://cxsjsxmooc.openjudge.cn/2019t2summerall/011/
    求排列的逆序数
    MergeSort
    归并排序
    复杂度: n*log(n)
    */
    #define _CRT_SECURE_NO_WARNINGS
    
    #include<iostream>
    using namespace std;
    long long MergeSort(int a[], int s, int e, int tmp[]);
    void Merge(int a[], int s, int m, int e, int tmp[]);
    //int a[] = { 2,6,3,4,5,1 };
    //int b[6];
    int a[100010];
    int b[100010];
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d", &a[i]);
        printf("%lld", MergeSort(a, 0, n - 1, b));
        return 0;
    
        //int size = sizeof(a) / sizeof(int);
        //long long result = MergeSort(a, 0, size - 1, b);
        //for (int k = 0; k < size; k++)
        //    cout << a[k] << " ";
        //cout << "
    " ;
        //cout << result << endl;
        //return 0;
    }
    /*归并排序 s :数组开始 e :数组结尾*/
    // 将数组 a 的局部 a[s, m] 和 a[m + 1, e] 合并到 tmp, 并保证 tmp 有序,然后再拷贝回 a[s, m]
    // 归并操作时间复杂度: O (e-m+1), 即 O (n)
    long long count(int a[], int s, int m, int e)
    //从大到小合并[s,m], [m+1,e] 
    {
        long long result = 0;
        int p1 = s;
        int p2 = m + 1;
        while (p1 <= m && p2 <= e)
        {
            if (a[p1] > a[p2])
            {
                result += e - p2 + 1;
                p1++;
            }
            else
            {
                p2++;
            }
        }
        return result;
    
    }
    
    long long MergeSort(int a[], int s, int e, int tmp[])
    {
        long long result = 0;
        if (s < e) /*当只有一个元素时,递归终止,直接调用merge函数,比较 13和27大小,最后排序*/
        {
            int m;// cut array into half
            m = s + (e - s) / 2;
            result += MergeSort(a, s, m, tmp);/* 排好序的数组 临时放在哪里? */
            result += MergeSort(a, m + 1, e, tmp);//分别求两边的逆序数 
            result += count(a, s, m, e);//然后再o(n)算左边和右边造成的逆序数 。此时要求左边和右边都是从大到小有序的,才能在o(n)时间内算出结果 
            Merge(a, s, m, e, tmp);//从大到小合并,确保排序 
        }
        return result;
    
    }
    void Merge(int a[], int s, int m, int e, int tmp[])
    //从大到小合并[s,m], [m+1,e] 
    {
        int i = 0;
        int p1 = s;
        int p2 = m + 1;
        while (p1 <= m && p2 <= e)
        {
            if (a[p1] > a[p2])
            {
                tmp[i++] = a[p1++];
            }
            else
            {
                tmp[i++] = a[p2++];
            }
        }
        while (p1 <= m)
            tmp[i++] = a[p1++];
        while (p2 <= e)
            tmp[i++] = a[p2++];
        for (int j = 0; j < e - s + 1; j++)
        {
            a[s + j] = tmp[j];
        }
    
    }
  • 相关阅读:
    poj 1743 Musical Theme 后缀数组
    poj 1743 Musical Theme 后缀数组
    cf 432D Prefixes and Suffixes kmp
    cf 432D Prefixes and Suffixes kmp
    hdu Data Structure? 线段树
    关于position和anchorPoint之间的关系
    ios POST 信息
    CALayers的代码示例
    CALayers详解
    ios中得sqlite使用基础
  • 原文地址:https://www.cnblogs.com/focus-z/p/11568639.html
Copyright © 2011-2022 走看看