zoukankan      html  css  js  c++  java
  • 倍增

    当我们想要知道从最快地从A走到B时,朴素的想法是找出任何一个点走任意步会到达的地方,但是这样太耗内存。

    但是实际上可以只记录走1,2,4,8,16步能到达的地方

    A出发:若跳8个格子(超过B了,放弃)

                      若跳4个格子(超过B了,放弃)

                      若跳2个格子(没超过B,跳吧)

                      若跳1个格子(没超过B,跳吧)

            从B出发:…………

            多么轻松的事情,只要一本很薄的小抄就可以了,最关键的是:它绝对不会连着跳两步都是跳相同的格子数,因为如果跳两次2个格子都是可行的话,那么它干嘛不跳4个格子捏?

    A出发跳1步到1(记录下来)

            从1出发跳1步到2(记录下来)

            …………(跳1步的记录完毕)

            从A出发跳2步?就是从A出发跳1步再跳1步的到的地方,翻看小抄,直接誊写从1出发跳1步会到的2这个格子作为A2步会到的格子。

            从1出发跳2步?跟刚才一样,直接誊写。

            …………(跳2步的记录完毕)

            从A出发跳4步?你还真去跳4步?不,它也就是等于从A出发跳2步到的2号点再跳2步会到的格子,那么我们直接誊写2号格子跳2步会到的格子就可以了。



    以下转自:http://jiayuzun.coding.me/2016/08/05/bz-template/

    算法理论

    • 朴素算法:记录下每个节点的父亲,使节点u,v一步一步地向上找父亲,直到找到相同的“祖先”,即是
      所求的答案,时间复杂度O(n)
    • 优化算法(倍增法):利用二进制的思想,想办法使一步一步向上搜索变成以2^k的向上跳。所以
      定义一个f[][]数组,使f[j][i]表示节点i的2^j倍祖先。

    算法实现

    1.预处理出所有节点的深度和父节点

    * BFS防止爆栈 无法处理孩子个数
    * DFS可能会爆栈 可以处理孩子个数 使用时建议扩栈
    

    2.处理各节点的所有祖先节点

    3.将所查询的两点上升到同一高度

    * 找到祖先(以2^k的高度向上找)
    * 未找到祖先,同时上升高度至找到公共祖先
    

    附加代码

    定义及初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #pragma comment(linker, "/STACK:10240000000,10240000000")//扩栈,要用c++交,用g++交并没有什么卵用。。。
    const int N = 100005;
    int n , m , pre[N] , rt[N], mcnt;//pre 邻接表数组 rt 求根节点 mcnt 邻接表下标变量
    bool vis[N];
    struct edge
    {
    int x , next;
    } e[N << 1]; //邻接表
    int dep[N] , f[17][N] , Lev , s[N];
    //dep[]储存深度 1<<16 < N f[j][i] 表示i的第2^j个祖先 s[]孩子个数
    void init()
    {
    memset(pre , -1 , sizeof(pre));
    memset(rt, 0, sizeof(rt));
    mcnt = 0;
    }

    算法函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    void addedge(int x, int y)//邻接表加边函数
    {
    e[mcnt].x = y,
    e[mcnt].next = pre[x],
    pre[x] = mcnt ++;
    }
    void dfs(int x , int fa)///也可以用bfs,但bfs不能统计节点孩子个数
    {
    dep[x] = dep[fa] + 1;
    f[0][x] = fa , s[x] = 1;
    for (int i = pre[x] ; i!=-1 ; i = e[i].next)
    {
    int y = e[i].x;
    if (y != fa)
    {
    dfs(y , x);
    s[x] += s[y];///节点x的孩子个数
    }
    }
    }
    // dfs处理后,要进一步处理得到节点的所有祖先
    // for (j = 1 ; 1 << j < n ; ++ j)
    // for (i = 1 ; i <= n ; ++ i)
    // {
    // f[j][i] = f[j - 1][f[j - 1][i]];
    // }
    // Lev = j - 1;
    void bfs(int rt)///不需要求孩子个数,同时防止暴栈
    {
    queue<int> q;
    q.push(rt);
    f[0][rt] = 0, dep[rt] = 1, vis[rt] = 1;
    while (!q.empty())
    {
    int fa = q.front();
    q.pop();
    for (int i = pre[fa] ; ~i ; i = e[i].next)
    {
    int x = e[i].x;
    if (!vis[x])
    {
    dep[x] = dep[fa] + 1;
    f[0][x] = fa , vis[x] = 1;
    q.push(x);
    }
    }
    }
    }
    int LCA(int x , int y)
    {
    if (dep[x] > dep[y])
    {
    swap(x , y);
    }
    for (int i = Lev ; i >= 0 ; -- i)///找y的第dep[y] - dep[x]个祖先
    if (dep[y] - dep[x] >> i & 1)//dep[y]-dep[x]刚好比2的i次方大时
    {
    y = f[i][y];
    }
    if (x == y)
    {
    return y;
    }
    for (int i = Lev ; i >= 0 ; -- i)//同一高度后开始找祖先
    if (f[i][x] != f[i][y])//不停的上次2的i次方,直到i==0
    {
    x = f[i][x] , y = f[i][y];
    }
    return f[0][x];
    }
    int get_kth_anc(int x , int k) ///找x的第k个祖先
    {
    for (int i = 0 ; i <= Lev ; ++ i)
    if (k >> i & 1)
    {
    x = f[i][x];
    }
    return x;
    }

  • 相关阅读:
    h5学习
    python 基础(十五) socket编程
    python 基础(十四) 正则表达式
    python 基础(十三) time模块
    python 基础(十二) 图片简单处理
    python 基础(十一) pickle 序列化
    python 基础(十) 面向对象
    python 基础(九) 文件操作
    python 基础(八) os模块
    python 基础(七) 异常处理
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9643404.html
Copyright © 2011-2022 走看看