zoukankan      html  css  js  c++  java
  • 归并排序及应用 (nyoj 117 求逆序数)

    求逆序数

    时间限制:2000 ms  |  内存限制:65535 KB
    难度:5
     
    描述

    在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

    现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。

    比如 1 3 2 的逆序数就是1。

     
    输入
    第一行输入一个整数T表示测试数据的组数(1<=T<=5)
    每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)
    随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。

    数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。
    输出
    输出该数列的逆序数
    样例输入
    2
    2
    1 1
    3
    1 3 2
    样例输出
    0
    1


    归并排序执行过程:
              1、执行归并排序函数时,把全部的数字一分为二,继续递归调用函数自身,左一半右一半的划分开,直到每一份里只有一个元素为止,停止划分。
             2、把划分开的元素按照大小顺序排列,先 1 1,合并为个数为 2 的数组,再把 2 2 按顺序大小要求合并成个数为 4 的数组,依次进行把所有元素按大小排序
                两两合并时两序列均已是有序序列

    如:
        4 1 3 10 7 3 5 0
        
        4 1 3 10 7 3 5 0

        4 1 3 10 7 3 5 0

        4 1 3 10 7 3 5 0 //每一组个数为 1 结束



    合并:  1 4 3 10 3 7 0 5

          1 3 4 10 0 3 5 7

    最后结果:   0 1 3 3 4 5 7 10




    本题利用归并时比较大小条件,因为两序列合并时都已经是有序的,所以一旦遇到前一个序列的a比后一个序列中的一个值大,那么前一个序列数的值a以后的数(包括a)都比后序列的值大,所以sum += (p3-s1+1); sum用long long.

    代码如下:
     1  
     2 //归并排序
     3 
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 long long sum = 0;
     7 void mergesort(int a[],int ,int );
     8 int main()
     9 {
    10     int a[1000300];
    11     int T,n,i;
    12     scanf("%d",&T);
    13     while(T--)
    14     {
    15         sum = 0;
    16         scanf("%d",&n);
    17         for(i=0;i<n;i++)
    18             scanf("%d",&a[i]);
    19         mergesort(a,0,n-1);
    20 
    21         printf("%lld
    ",sum);
    22     }
    23     return 0;
    24 }
    25 
    26 void merge(int a[],int s1,int e1,int s2,int e2)
    27 {
    28     //s1-e1为左数组
    29     //s2-e2为右数组
    30     int j = 0,i,p1 = s1,p2 = e2,p3 = e1;
    31     int *temp = (int*)malloc(sizeof(int)*(e2-s1+5));
    32 
    33     while(s1 <= e1 && s2 <= e2)
    34     {
    35         if(a[s1] <= a[s2])
    36         {
    37             temp[j++] = a[s1++];continue;
    38         }
    39         else
    40         {
    41             sum += (p3-s1+1);
    42             temp[j++] = a[s2++];continue;
    43         }
    44     }
    45     while(s1 <= e1)//如果左边还有
    46         temp[j++] = a[s1++];
    47 
    48     while(s2 <= e2)//如果右边还有
    49         temp[j++] = a[s2++];
    50 
    51     j = 0;
    52     for(i = p1;i <= p2;i++)//把排好序的数组存回原来的地方
    53         a[i] = temp[j++];
    54 
    55     delete temp;//记得释放指针
    56 }
    57 void mergesort(int a[],int left,int right)
    58 {
    59     //先一直拆分左边,知道拆分的只剩下一个元素为止,然后以一个元素为对称,右边也只有一个元素,然后合并两个元素
    60     //一直这样向上合并,先1 1合并,然后2 2 合并 4 4..8 8..16 16...知道所有元素都已经合并完成
    61     //带合并的两列数字都已经是有序的
    62     int mid;
    63     if(left < right)
    64     {
    65         mid = (left+right)/2;
    66         mergesort(a,left,mid);//左拆分
    67         mergesort(a,mid+1,right);//右拆分
    68 
    69         merge(a,left,mid,mid+1,right);//合并
    70     }
    71 }
    72         








  • 相关阅读:
    Linux 多线程编程 实例 1
    面试题-链表反转c实现
    information_schema.TABLES
    mongodb遇到的错误
    MySQL优化的奇技淫巧之STRAIGHT_JOIN
    mongodb安装
    XtraBackup安装
    提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)
    我用 TypeScript 语言的七个月
    Grunt之添加文件监视:Grunt-watch (已备份)
  • 原文地址:https://www.cnblogs.com/ldy-miss/p/5888735.html
Copyright © 2011-2022 走看看