基本的LCA问题的实现

LCA问题可以归约为RMQ问题求解。
归约方法为:做一次DFS(Euler Tour),在DFS过程中,记录三个数组的值:
E[i]:在Euler Tour过程中途经的结点编号
L[i]:在Euler Tour过程中途经的结点的层次(从根结点算起的深度)

RMQ问题可以有多种实现方法,本程序采用了Sparse Table方法。
//LCA problem.
#include <iostream>
#include <cmath>
using namespace std;
const int MAXN = 110, MAXNLG = 16;
struct node {
    int v;   //number of the node
    node *next;
};
node *tree[MAXN];
int E[2*MAXN], L[2*MAXN], R[MAXN], visit[MAXN];
int ST[2*MAXN][MAXNLG];
int n, m;    //n:number of nodes, m:number of edges
int cnt;     //counter for the Euler tour
void init()
{
    int i, j, k;
    node *p;
    scanf("%d%d", &n, &m);
    for (i=1; i<=m; i++)
    {
        scanf("%d%d", &j, &k);
        p = new node;
        p->v = k;
        p->next = tree[j];
        tree[j] = p;

        p = new node;
        p->v = j;
        p->next = tree[k];
        tree[k] = p;
    }
}
void dfs(int i, int depth)
{
    node *p;
    if (visit[i] == 2) return;  //node i has visited over
    cnt++;
    E[cnt] = i;
    if (visit[i]==0)
        L[cnt] = depth;
    else
        L[cnt] = L[R[i]];

    //if node i hasn't visited, then it's the first time visit
    if (R[i] == -1)
      R[i] = cnt;
    if (visit[i] ==0)
    {
        visit[i]++;
        //visit each child of node i
        for (p = tree[i]; p; p=p->next)
            dfs(p->v, depth+1);
        visit[i]++;
    }

}
void process1()
{
    int i;
    memset(R, -1, sizeof(R));
    dfs(1, 0);
    for (i=1; i<=cnt; i++)
      printf("%d ", E[i]);
    printf("/n");
    for (i=1; i<=cnt; i++)
      printf("%d ", L[i]);
    printf("/n");
    for (i=1; i<=n; i++)
      printf("%d ", R[i]);
}
void process2(int M[2*MAXN][MAXNLG], int A[2*MAXN], int N)
{
    int i, j;
    for (i=1; i<=N; i++)
      M[i][0] = i;
    for (j=1; (1<<j)<=N; j++)
      for (i=1; i+(1<<j)-1<=N; i++)
        if (A[M[i][j-1]] < A[M[i+(1<<(j-1))][j-1]])
          M[i][j] = M[i][j-1];
        else
          M[i][j] = M[i+(1<<(j-1))][j-1];
}
int rmq(int M[2*MAXN][MAXNLG], int A[2*MAXN], int i, int j)
{
    int k;

    k = floor(log(j-i+1)/log(2));
    if (A[M[i][k]] < A[M[j-(1<<k)+1][k]])
      return M[i][k];
    else
      return M[j-(1<<k)+1][k];
}

int main()
{
    int i, j, k, x, y;
    init();
    process1();
    process2(ST, L, cnt);
    while (true)
    {
        scanf("%d%d", &i, &j);
        if (i==0) break;
        x = R[i];  y = R[j];
        if (x > y)
            swap(x, y);
        k = rmq(ST, L, x, y);
        i = E[k];
        printf("%d/n", i);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值