zoukankan      html  css  js  c++  java
  • [jobdu]数组中的逆序对

    http://ac.jobdu.com/problem.php?pid=1348 数组中的逆序对也是个常见的题目,算法导论中也有一些描述,参考:http://www.cnblogs.com/wuyuegb2312/p/3156286.html。解法自然有朴素解法O(n^2)不表,然后有基于归并排序的,可以O(n*logn)。

    1.在归并排序中,同样是对一个数组分为两段处理,在处理这两段时,并不会影响右段元素与左段元素的逆序关系,只有在归并时才会改变。
    2.归并时的改变方式和插入排序是类似的:右段中取出元素放在左段其余所有元素前面时,相当于左段整体后移,后移的元素数就是这个逆序数。
    3.由于归并排序使用的是分治法,将每次归并的逆序数累加,最后结果就是总的逆序数。并且,归并排序的时间复杂度是O(nlogn),优于插入排序。
    根据以上的探讨,归并排序稍作修改,就获得了时间复杂度为O(nlogn)的寻找逆序对总数的算法了。

    本来也到此结束了,后来又发现一个基于树状数组的解法(http://boj.haotui.com/thread-2792-1-1.html),不过还是太高级,就不深入研究了。树状数组略看了一下,和数字的和有关,比如可以解决多数求和的问题。“采用累加的方法还有一个局限,那就是,当修改掉数组中的元素后,仍然要你求数组中某段元素的和,就显得麻烦了。所以我们就要用到树状数组,他的时间复杂度为O(lgn)。”(http://www.cnblogs.com/zhangshu/archive/2011/08/16/2141396.html

    具体代码:

    1.C++中的数组新建和删除是 int* arr = new int[n]; delete arr[];
    2.出现HEAP CORRUPTION DETECTED往往是操作new申请的内存溢出。比如我一开始调用了mergeCount(0, n)就错误的访问了a[n]。 http://blog.sina.com.cn/s/blog_511703010100lz33.html

    3.借鉴了别人的写法,在一个循环里就把双指针移动写完了,主要是把到头后的判断加上,一开始使用||。
    4.因为mergeSort的空间复杂度是o(n),所以也可以一开始就申请好数组,就不用在递归里不断new和delete了。
    5.mergeCount的时候,当右边的小于左边的时,要注意计算对逆序数目。

    #include <cstdio>
    using namespace std;
    long long tot;
    int a[100005];
    void mergeCount(int l, int r) // [l, m], [m+1, r]
    {
        if (l >= r) return;
        int m = (l + r) / 2;
        mergeCount(l, m);
        mergeCount(m+1, r);
        int* tmp = new int[r-l+1];
        int i = l;
        int j = m+1;
        int k  = 0;
        while (i <= m || j <= r)
        {
            if (i > m)
            {
                tmp[k++] = a[j++];
            }
            else if (j > r)
            {
                tmp[k++] = a[i++];
            }
            else if (a[i] <= a[j])
            {
                tmp[k++] = a[i++];
            }
            else
            {
                tmp[k++] = a[j++];
                tot += (m-i+1);
            }
        }
        for (int j = 0; j <= (r - l); j++)
        {
            a[l+j] = tmp[j];
        }
        delete[] tmp;
    }
       
    int main()
    {
        int n;  
        while(scanf("%d", &n) == 1)  
        {  
            for(int i=0; i<n; ++i)  
                scanf("%d", &a[i]);              
            tot = 0;  
            mergeCount(0, n-1);  
            printf("%lld
    ", tot);  
        }  
    }
    

      

  • 相关阅读:
    zoj 1239 Hanoi Tower Troubles Again!
    zoj 1221 Risk
    uva 10192 Vacation
    uva 10066 The Twin Towers
    uva 531 Compromise
    uva 103 Stacking Boxes
    稳定婚姻模型
    Ants UVA
    Golden Tiger Claw UVA
    关于upper、lower bound 的探讨
  • 原文地址:https://www.cnblogs.com/lautsie/p/3276703.html
Copyright © 2011-2022 走看看