zoukankan      html  css  js  c++  java
  • (分治思想)(归并排序)C

    Description

    In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
    9 1 0 5 4 ,

    Ultra-QuickSort produces the output
    0 1 4 5 9 .

    Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

    Input

    The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

    Output

    For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

    Sample Input

    5
    9
    1
    0
    5
    4
    3
    1
    2
    3
    0
    

    Sample Output

    6
    0
    

    本题其实只要是明白了归并排序,至于分治思想和逆排序就很简单了

    归并法排序

    思想概述:其实归并排序就是分治思想的一种应用,就是每次用二分的方式,每次将序列分成两部分,然后知道分成每一部分两个数为止,
    在这一整块作为一部分,依次从该该整区间的左区间第一个数开始和右边(即从mid右面的)第一个数作比较,将小的放到合并序列中
    这样就将该小的范围排好序了。之后一次排序,知道当前区间为整个大区间为止(详解http://blog.csdn.net/u014665013/article/details/38035359

    分治思想  http://www.doc88.com/p-98237060283.html

    题目本质就是求逆序对了,简单介绍一下。逆序对是指在序列{a0,a1,a2...an}中,若ai<aj(i>j),则(ai,aj)上一对逆序对。而逆序数顾名思义就是序列中逆序对的个数。例如: 1 2 3是顺序,则逆序数是0;1 3 2中(2,3)满足逆序对的条件,所以逆序数只有1; 3 2 1中(1,2)(1,3)(2,3)满足逆序对,所以逆序是3。由定义不能想象,序列n的逆序数范围在[0,n*(n-1)/2],其中顺序时逆序数为 0,完全逆序时逆序数是n*(n-1)/2。

    可以利用归并排序时计算逆序个数,时间复杂度是nlog2n,而空间复杂度2n。 利用归并求逆序是指在对子序列s1和s2在归并时,若s1[i]>s2[j](逆序状况),则逆序数加上s1.length-i,因为s1中i后面的数字对于s2[j]都是逆序的 

    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define MAX 500001
    
    int n, a[MAX], t[MAX];    //a[]为输入序列 t[]为合并序列 应该注意的是,每次t[]数列都是临时的,
                                //只在每次当前区间的排序中记录有序序列
    __int64 sum;        //逆序对个数
    
    // 归并  
    void Merge(int l, int m, int r)
    {
    	//p指向输出区间
        int p = 0;
    	//i、j指向2个输入区间
        int i=l, j=m+1;                 //2个输入区间都不为空时
    	
        while(i<=m && j<=r)
        {                            // 取关键字小的记录转移至输出区间	
            if(a[i]>a[j])         //在左边的区间的当前访问的数大于右区间的
            {
                t[p]=a[j];        //将右区间数合并到合并数列中
                p++;                  
                j++;               //如果合并了,就将右区间的加1
    			<span style="color:#ff0000;">sum+=m-i+1; </span>      //a[i]后面的数字对于a[j]都是逆序的 例如1(L) 2 7 9 10(mid) 3 4 6 7 8 (r)                                                                                                                                                        ^(当前位置)这样在7后面的(当然                                                                            小于    =10)的所有数就都大于后面的了所以这样加
            }
            else              //在左边的区间的当前访问的数小于或等于右区间的
    		{	
                t[p] = a[i];    //将左区间数合并到合并数列中
    			p++;              
    			i++;
    		}
        }
     
        while(i <= m)         //如果左区间中还存在没有进入合并序列的数,就让剩下的进合并序列
    		t[p++] = a[i++];
        while(j <= r)       //如果左区间中还存在没有进入合并序列的数,就让剩下的进合并序列
    		t[p++] = a[j++];
    
        for (i=0; i<p; i++)	 // 归并完成后将结果复制到原输入数组
            a[l+i] = t[i];
    }
    
    //   归并排序 
    void MergeSort(int l, int r)
    {
        int m;
        if (l<r)
        {                           // 将长度为n的输入序列分成两个长度为n/2的子序列 	
            m = (l+r)/2;             	
            MergeSort(l, m);// 对两个子序列分别进行归并排序
            MergeSort(m + 1, r);     	 
           <span style="color:#cc0000;"> Merge(l, m, r);//子序列合并成最终有序序列    //其实完全可以将Merge()函数放在该位置
    </span>    }
    }
    
    int main()
    {
        int i;
        while(1)
        {
            scanf("%d", &n);
            if (n == 0) 
    			break;
            sum=0;
            for(i = 0; i < n; i++)
                scanf("%d", &a[i]);
            MergeSort(0, n-1);
            printf("%I64d
    ", sum);
        }
        //system("pause");
        return 0;
    }


     

  • 相关阅读:
    构建之法第十三~十七章阅读
    构建之法第十,十一,十二章阅读
    构建之法第八,九,十章阅读
    Sprint会议计划
    作业6
    作业5 四则运算 测试与封装 5.2
    作业5 四则运算 测试与封装 5.1
    构建之法2
    做汉堡
    构建之法阅读
  • 原文地址:https://www.cnblogs.com/zswbky/p/5432122.html
Copyright © 2011-2022 走看看