zoukankan      html  css  js  c++  java
  • 分治算法

    分治算法

    在提高组中应该考不了什么分值算法,咕咕咕,应该会考,比如二分,归并排序等知识点。

    下面就对二分和分治排序做一个小总结。


    一,何为分治算法

    如字面意思,分而治之,分治算法是一种将较大规模的问题分解成几个较小规模的问题,通过对较小规模问题的求解达到对整个问题的求解,

    这也是贪心,DP等的主要想法。

    二,二分

    二分的定义:将问题分解成两个较小的问题的方法叫做二分法。

    二分的基本用途:在单调序列或单调函数中做查找操作,如果某个问题的答案具有单调性,那么我们就可以通过二分把对问题的求解变为对问题答案的判定

    通过理论复杂度分析可知,对答案的二分判定的复杂度要小于对问题求解的复杂度。

    三,二分法

    在一个单调序列中,每次都将序列分为两部分,判断解在哪个部分并调整上下界,直到找到目标元素,每次二分以后都将舍弃一半的元素,因此二分效率很高。

    二分法的实现

    1,整数定义域上的二分

    inline void divide(int l,int r)
    {
        l=1,r=n;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid;
        }
        return;
    }//伪代码 

    2,实数域上的二分查找(一般不用吧qwq,不太会

    四,二分法的常见模型

    1,二分答案:最小值最大(或最大值最小)类的问题常常用二分解决,就是二分最值后配合其他算法检验其合理性,将最优值问题转化为判定性问题。

    2,二分查找

    3,代替三分

    五,归并排序

    归并排序分为两个步骤,分 和 和。

    分:依次拆分区间为两个区间使每个区间有序,当拆分到每个区间只有一个元素时,每个区间就有序了。

    和:将每两个有序的序列合并为一个有序的序列。

     

    代码实现:

     1:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    
    using namespace std;
    
    int num[maxn],n;
    
    inline void merge(int *num,int *a,int l,int r)
    {
        int i=l,j,k=l,mid=(l+r)>>1;
        for(i=l,j=mid+1;i<=mid&&j<=r;k++)
        {
            if(num[i]<=num[j]) a[k]=num[i++];
            else a[k]=num[j++];
        }
        while(i<=mid) a[k++]=num[i++];
        while(j<=r) a[k++]=num[j++];
    }
    
    inline void m_sort(int *num,int *a,int l,int r)
    {
        if(l==r)
        {
            a[l]=num[l];
        }
        else
        {
            int t[maxn];
            int mid=(l+r)>>1;
            m_sort(num,t,l,mid);
            m_sort(num,t,mid+1,r);
            merge(t,a,l,r);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
           scanf("%d",&num[i]);
        m_sort(num,num,1,n);
        for(int i=1;i<=n;i++)
            printf("%d ",num[i]);
        return 0;
    }
    View Code

     2:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005 
    
    using namespace std;
    
    int num[maxn],n,a[maxn];
    
    inline void m_sort(int l,int r)
    {
        if(l==r) return;
        int mid=(l+r)>>1;
        m_sort(l,mid);
        m_sort(mid+1,r);
        int p1=l,p2=mid+1;
        for(int i=l;i<=r;i++)
        {
            if(p1<=mid&&p2<=r)
            {
                if(num[p1]<num[p2]) a[i]=num[p1++];
                else a[i]=num[p2++];
            }
            else
            {
                if(p1<=mid) a[i]=num[p1++];
                else a[i]=num[p2++];
            }
        }
        for(int i=l;i<=r;i++)
           num[i]=a[i];
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
        m_sort(1,n);
        for(int i=1;i<=n;i++)
            printf("%d ",num[i]);
        return 0;
    } 
    View Code

    个人觉得第二种代码实现比较好理解,也比较容易与上面的理论结合。

    六,归并排序求逆序对

    1,逆序对:如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数。

    我们考虑一下如何在合并的过程中求解逆序对,合并的过程是将两个有序的序列合并成一个序列,合并过程已经保证了序列a的编号小于序列b的编号,而我们知道

    每个单独的序列是有序的,所以其中不可能存在逆序对,逆序对只可能存在于要合并的两个有序区间之间,所以我们只需要在合并的时候统计一下就好。

    如果合并过程中,前一个序列中的某个数大于后一个序列的某个数,那么前面那个序列中从当前数开始到mid的所有数都和后一个序列中那个数构成逆序对。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define maxn 500005 
    
    using namespace std;
    
    int num[maxn],n,a[maxn];
    long long ans;
    
    inline void m_sort(int l,int r)
    {
        if(l==r) return;
        int mid=(l+r)>>1;
        m_sort(l,mid);
        m_sort(mid+1,r);
        int p1=l,p2=mid+1;
        for(int i=l;i<=r;i++)
        {
            if(p1<=mid&&p2<=r)
            {
                if(num[p1]<=num[p2]) a[i]=num[p1++];
                else a[i]=num[p2++],ans+=(long long)mid-p1+1;
            }
            else
            {
                if(p1<=mid) a[i]=num[p1++];
                else a[i]=num[p2++];
            }
        }
        for(int i=l;i<=r;i++)
           num[i]=a[i];
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
        m_sort(1,n);
        printf("%lld",ans);
        return 0;
    } 
    View Code

    最后祝各位OIer NOIP 2019 RP++ SCORE++

  • 相关阅读:
    php ajax分页的例子,在使用中
    PHP远程文件管理,可以给表格排序,遍历目录,时间排序
    背景变暗的div可拖动提示窗口,兼容IE、Firefox、Opera
    CSS简洁的左侧菜单(侧拉菜单,向右显示)
    无间断循环滚动(兼容IE、FF)
    poj 1007 求逆序数
    poj 1775 简单搜索
    面向对象之继承和组合浅谈
    在flex中导入fl包
    C99中包括的特性
  • 原文地址:https://www.cnblogs.com/Hoyoak/p/11351804.html
Copyright © 2011-2022 走看看