• 基本算法——归并排序


    理论概念

    定义

    归并排序是基于分治法的排序方法,其时间复杂度为O(nlogn)

    原理

    没什么比一张Gif图片来解释排序算法更清爽了。

    所以我就从Python的教程网站上扒了一张233

    可以看到,归并排序,顾名思义。归,并。

    核心代码

    由于形式纷杂不好统一,这里仅列举一种展现方法。但其精髓仍是归与并的分治思想。

    void merge(int l,int r)
    {
        if(l>=r) return;
        int mid=(l+r)/2;
        merge(l,mid);
        merge(mid+1,r);
        int i=l,j=mid+1,k=l-1;//此时的i是第一个数组的左端点,j是第二数组的左端点 
        while(i<=mid&&j<=r)
        { 
           k++;
            if(f[i]>f[j])
            { //拿两个的首项做对比,小的直接排入。 
                f1[k]=f[j];
                ans+=mid-i+1;
                ans%=mod;
                j++;
            }
            else {
                f1[k]=f[i];
                i++;
            }
        }
        while(i<=mid){k++;f1[k]=f[i];i++;}//处理剩余 
        while(j<=r){k++;f1[k]=f[j];j++;}
        for(int i=l;i<=r;i++)
        {//这里,归。 
           f[i]=f1[i];
        }
    }

    题目中的Show Time

    逆序对

    归并排序常被应用于关于逆序对的问题中。什么是逆序对问题?

    对于一个序列a,若i<j且有A[i]>A[j],则称A[i]、A[j]构成逆序对

    归并排序每次把序列二分,递归对左右俩半排序,然后合并两个有序序列。在对左右两半排序时,可以把左右两半各自内部的逆序对数作为子问题计算。故只需考虑“左边一半里一个较大的数”与“右边一半里一个较小的数”构成逆序对的情形。求出这种情形的个数。

    在合并时,比较A[i]与A[j]的大小。如若A[j]小,那么A[i]~A[mid]都大于A[j]。他们都会与A[j]构成逆序对。可以顺便统计到答案中去。

    代码实现如下:

    void merge(int l,int mid,int r){
        //合并a[l~mid]与a[mid+1~r]
        //a是待排序数组,b是临时数组,cnt是逆序对的个数
        int i=l,j=mid+1;
        for(int k=l;k<=r;k++){
            if(j>r||i<=mid&&a[i]<=a[j]){
                b[k]=a[i++];
            }
            else{
                b[k]=a[j++];
                cnt+=mid-i+1;
            }
        }
        for(int k=l;k<=r;k++){
            a[k]=b[k];
        } 
    } 

    火柴排队 Noip2013提高组Day1T2

     难就难在,这题怎么想到是个逆序对。(可他就是个逆序对…)

    思考一下,首先必然有一种对应关系。而怎么能让这个最小距离最小呢?其实,排个序,然后大对大,小对小就能保证这个差值的绝对值之和一定是最小了。(那个所谓的平方,不如直接求abs,否则有点计算冗余)。

    前面的具体思路我会在7.14校模拟里的一篇博文放出来。在这里咱们具体讨论一下关于他是个逆序对的问题。

    我们得到一个映射关系之后,发现是乱序。只要我们将其复原到从小到大的顺序,那么就等于从末状态反向抵达初状态。那么这个交换步骤发生于哪里呢?理所当然,交换步骤是发生在逆序对解决归并排序的“归”之中的。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=100005,mod=99999997;
    int n;
    struct node{
     ll x;
     int id;
    }a[N],b[N];
    int c[N],d[N],f[N],f1[N];
    ll ans=0;
    ll read(){
        ll sum=0,f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-')f=-1;
            ch=getchar();
        }
         while(ch>='0'&&ch<='9'){
            sum=(sum<<3)+(sum<<1)+ch-'0';
            ch=getchar();
        }
        return sum*f;
    }
    int comp(node a,node b)
    {
        return a.x<b.x;
    }
    void merge(int l,int r)
    {
        if(l>=r) return;
        int mid=(l+r)/2;
        merge(l,mid);
        merge(mid+1,r);
        int i=l,j=mid+1,k=l-1;
        while(i<=mid&&j<=r)
        { 
           k++;
            if(f[i]>f[j])
            { 
                f1[k]=f[j];
                ans+=mid-i+1;
                ans%=mod;
                j++;
            }
            else {
                f1[k]=f[i];
                i++;
            }
        }
        while(i<=mid){k++;f1[k]=f[i];i++;}
        while(j<=r){k++;f1[k]=f[j];j++;}
        for(int i=l;i<=r;i++)
        {
           f[i]=f1[i];
        }
    }
    int main(){
    //    freopen("match.in","r",stdin);
    //    freopen("match.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)
        { a[i].x=read();
          a[i].id=i;}
        for(int i=1;i<=n;i++)
        { b[i].x=read();
          b[i].id=i;}
        sort(a+1,a+n+1,comp);
        sort(b+1,b+n+1,comp);
        for(int i=1;i<=n;i++)
        {
            c[a[i].id]=i;//c数组保存的是:在i位置保存的是在a数组的第几个位置 
            d[i]=b[i].id;
        }    
        for(int i=1;i<=n;i++){
            f[i]=d[c[i]];//f中存的就是b的ID与A的映射 
        }
        merge(1,n);
        cout<<ans;
        return 0;
    } 

    能想到逆序对,说实话挺绕的。不适合作为入门级样题来做。

  • 相关阅读:
    存储与服务器的连接方式对比(DAS,NAS,SAN)
    FreeNAS系统总结
    FreeNAS-9.10虚拟机测试安装
    rsync实时同步服务部署
    无限循环与嵌套循环
    几种循环语句
    选择结构if
    java引用数据类型
    java运算符的优先级
    java运算符-逻辑、三元运算符
  • 原文地址:https://www.cnblogs.com/Uninstalllingyi/p/11186426.html
Copyright © 2020-2023  润新知