• 倍增算法的一些应用


    我所了解的倍增算法

    我所了解的倍增算法大体是这样的,当我们想知道2^n次方这么个长度范围内的某个值(如最大值或者最小值),如果我知道了所有的2^(n-1)次方长度范围内的值,这样我就可以通过我所知道的这些值中算出我要的值。具体在定义的时候一般是这样的

    anc[i][k] 表示以i开头,长度为2^k次方的这么一个区间我们所要的值(这里以最小值为例),那么当我知道一个数组的所有数之后,我就可以用nlogn的时间来进行预处理,然后可以用logn的时间来获得任意一个区间的最小值

    具体可以这样来做

    for (int i=1;i<=n;i++) anc[i][0] = a[i];
    for (int k=1;k<=20;k++)
        for (int i=1;i<=n;i++) 
            anc[i][k] = min(ans[i][k-1], ans[i + (1<<(k-1))][k-1]);

    因为我们知道任意一个区间都可以有2的多个次方组成,故可以用多个2^k来组成一个区间,这样就可以在logn的时间求出我们想要的值

    倍增算法的应用

    1,在求最大值及最小值上的应用

    正如上面所说的,倍增算法可以用来求最小值,同时也可以用来求最大值,只要把min改成max就可以了,这也是所说的RMQ算法

    2,用来求LCA

    LCA就是最近公共祖先,就是一棵树,求两个结点的最近公共祖先,我们也可以像刚才的代码一样预处理出anc数组

    for (int i=1;i<=n;i++) anc[i][0] = fa[i];
    for (int k=1;k<=20;k++)
        for (int i=1;i<=n;i++) 
            anc[i][k] = min(ans[i][k-1], ans[i + (1<<(k-1))][k-1]);

    只是预处理的时候距离为1的祖先应该是其父亲结点,然后在求两个结点的最近公共祖先时,先把深度的结点上升到和深度较小的结点一样的深度,具体的上升方法也用anc这个数组来升,就是把u节点上升到第H个祖先的位置,即长度为H,起始位置为u,然后在应用anc数组,找到两个结点的Lca,具体看下面代码

    上升
    void swim(int &x,int H){for (int i=0;H>0;i++){if (H&1) x=anc[x][i]; H/=2; }}
    
    获得LCA
    int Lca(int u,int v)
    {
         int i;
         if (dep[u]>dep[v]) swap(u,v); //printf("%d %d
    ",u,v);
         swim(v,dep[v]-dep[u]); //printf("%d
    ",v);
         if (u==v) return u;
         for (; ;)
         {
              for (i=0;anc[u][i]!=anc[v][i];i++); //printf("%d %d %d %d
    ",u,anc[u][i],v,anc[v][i]);
              if (i==0) return anc[u][0];
              u=anc[u][i-1]; v=anc[v][i-1];
         }
         return -1;
    }

    3,扩展应用

    可以看出,只要是满足结合律,我们都可以用这个方法来求,如gcd(最大公约数),没想到吧,一个区间的最大公约数也可以这样来求,其他的只要满足结合律关系的,在对区间询问时,都可以考虑一下这样的算法

    4,换位思考后的应用

    我们一般都是考虑区间里面的某个值,可不可以倒过来,考虑值,然后存区间呢?

    曾经碰到过这样一个题:

      X轴上有很多区间,现在有m个询问,给你一个区间[L,R],问这个区间内最多有多少个不重复的区间

    这个题就可以考虑倍增算法,anc[i][k]表示以i开始,2^k次方个不想交的区间的最右边的位置的最小值,于是以同样的做法,稍加处理就可以得到任意一个区间的答案

    以上便是我给出的几个方面的应用,当然1,2都是显然的,而3,4都是要求结合实际问题来讨论的

  • 相关阅读:
    logdump命令使用
    centos 添加用户并赋予sudo权限
    ogg进程解析
    xxl-job-executor2.2.0添加为默认执行器(docker方式)
    mysql设置数据库默认编码和表名不区分大小写
    linux-curl工具使用
    docker通过dockerfile打java项目镜像
    通过shell检查服务并发送mail告警(shell监控脚本)
    esxi6.5安装教程
    Vmware Vcenter6.5 配置集群和主机
  • 原文地址:https://www.cnblogs.com/chensunrise/p/4859173.html
Copyright © 2020-2023  润新知