LCA最近公共祖先问题 倍增

小米Git

http://www.nowcoder.com/questionTerminal/e9ff41269a7e49519b87fe7d9fd0d477

这道题很明显的LCA了

  1. 一般求LCA方法
  • 先建树,求
  • 如果深度不相同,先把深的那个点向上爬到同一层
  • 如果已经跳到相同层了,就一起向上跳,直到


2. 倍增求LCA

  • 在1的基础上改进,引入了一个预处理好的表来记录往上跳步的祖先

  • 需要先把这个表预处理出来(可以在建树的时候就预处理出跳表)

    void dfs_build(vector<string>& mtx, int u, int father) {
      vis[u] = true;
      level[u] = level[father]+1;          //更新当前递归到的点的深度
      up[u][0] = father;                   //向上跳2^0=1,就是跳到爹上
    
      for(int i=1; (1<<i)<=level[u]; i++)  //2^j = (2^j-1) + 2^(j-1)
          up[u][i] = up[up[u][i-1]][i-1];
    
      for(int i=0; i<n; i++) {
          int v = i;
          if(v == u || vis[v] || mtx[u][v] == '0') continue ;
          fa[v] = u;                      //建立父子关系
          dfs_build(mtx, v, u);
      }
    }    

    求LCA

    int lca(int u, int v) {
      if(level[u] > level[v]) swap(u, v);
      for(int i=L; i>=0; i--)
          if(level[u] <= level[v]-(1<<i)) 
              v = up[v][i];
      if(u == v) return u;
      for(int i=L; i>=0; i--)
          if(up[u][i] == up[v][i]) continue ;
          else {
              u = up[u][i];
              v = up[v][i];
          }
      return up[u][0];
    }


3. Tarjan求LCA (离线算法)

  • 不会

本题代码

#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>

#define MAXN (2048)
#define ll long long 
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#define show(x...) \
    do { \
        cout << "\033[31;1m " << #x << " -> "; \
        err(x); \
    } while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO {

    char print_f[105];
    void read() { }
    void print() { putchar('\n'); }

    template <typename T, typename... T2>
        inline void read(T &x, T2 &... oth) {
            x = 0;
            char ch = getchar();
            ll f = 1;
            while (!isdigit(ch)) {
                if (ch == '-') f *= -1; 
                ch = getchar();
            }
            while (isdigit(ch)) {
                x = x * 10 + ch - 48;
                ch = getchar();
            }
            x *= f;
            read(oth...);
        }
    template <typename T, typename... T2>
        inline void print(T x, T2... oth) {
            ll p3=-1;
            if(x<0) putchar('-'), x=-x;
            do{
                print_f[++p3] = x%10 + 48;
            } while(x/=10);
            while(p3>=0) putchar(print_f[p3--]);
            putchar(' ');
            print(oth...);
        }
} // namespace FastIO
using FastIO::print;
using FastIO::read;

int n, m, Q, K;
#if 0 //非倍增的普通求LCA
bool vis[MAXN];
int level[MAXN], fa[MAXN];                  //fa[i]表示i的父节点

#define cls(x) (memset(x, false, sizeof(x)))

class Solution {
public:
    int n;

    void init(vector<string>& mtx) {
        n = mtx.size();
        cls(level), cls(fa), cls(vis);
    }

    void dfs_build(vector<string>& mtx, int u, int dep) {
        vis[u] = true;
        level[u] = dep;                     //更新当前递归到的点的深度
        for(int i=0; i<n; i++) {
            int v = i;
            if(v == u || vis[v] || mtx[u][v] == '0') continue ;
            fa[v] = u;                      //建立父子关系
            dfs_build(mtx, v, dep+1);
        }
    }

    int getSplitNode(vector<string>& mtx, int u, int v) {
        init(mtx);
        dfs_build(mtx, 0, 0);               //先dfs建树

        int lu = level[u], lv = level[v];

        while(lu < lv)                      //把u和v爬到同一层
               lv = level[fa[v]], v = fa[v];
        while(lv < lu) 
            lu = level[fa[u]], u = fa[u];

        while(u != v)                       //u和v一起向上爬
            u = fa[u], v = fa[v];
        return u;
    }
};

#else  //倍增求LCA

#define L (20)
bool vis[MAXN];
int level[MAXN], fa[MAXN];                  //fa[i]表示i的父节点
int up[MAXN][L+5];                            //跳表

#define cls(x) (memset(x, false, sizeof(x)))

class Solution {
public:
    int n;

    void init(vector<string>& mtx) {
        n = mtx.size();
        cls(level), cls(fa), cls(vis), cls(up);
    }

    void dfs_build(vector<string>& mtx, int u, int father) {
        vis[u] = true;
        level[u] = level[father]+1;          //更新当前递归到的点的深度
        up[u][0] = father;                   //向上跳2^0=1,就是跳到爹上

        for(int i=1; (1<<i)<=level[u]; i++)  //2^j = (2^j-1) + 2^(j-1)
            up[u][i] = up[up[u][i-1]][i-1];

        for(int i=0; i<n; i++) {
            int v = i;
            if(v == u || vis[v] || mtx[u][v] == '0') continue ;
            fa[v] = u;                      //建立父子关系
            dfs_build(mtx, v, u);
        }
    }

    int lca(int u, int v) {
        if(level[u] > level[v]) swap(u, v);
        for(int i=L; i>=0; i--)
            if(level[u] <= level[v]-(1<<i)) 
                v = up[v][i];
        if(u == v) return u;
        for(int i=L; i>=0; i--)
            if(up[u][i] == up[v][i]) continue ;
            else {
                u = up[u][i];
                v = up[v][i];
            }
        return up[u][0];
    }

    int getSplitNode(vector<string>& mtx, int u, int v) {
        init(mtx);
#if 0
        fori(0, n-1)
            forj(0, n-1)
                if(mtx[i][j] == '1') printf("%d %d\n", i, j);
#endif
        dfs_build(mtx, 0, 0);               //先dfs建树
#if 0
        forarr(level, 0, n-1, "level");
        forarr(fa, 0, n-1, "fa   ");
#endif
        return lca(u, v);
    }
};

#endif


#if 1
int main() {
#ifdef debug
    freopen("test", "r", stdin);
    // freopen("out_main", "w", stdout);
    clock_t stime = clock();
#endif

    vector<string> mtx = {
        "0110000000","1000101000","1001000000","0010000000","0100000101",
        "0000001000","0100010010","0000100000","0000001000","0000100000"
    };
    Solution s;
    int U = 6, V = 7;
    cout << s.getSplitNode(mtx, U, V);


#ifdef debug
    clock_t etime = clock();
    printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
    return 0;
}


#endif
全部评论

相关推荐

11-03 14:38
重庆大学 Java
AAA求offer教程:我手都抬起来了又揣裤兜了
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务