zoukankan      html  css  js  c++  java
  • poj1330Nearest Common Ancestors LCA问题 dfs+rmq

    题目意思很简单就是求两个节点的LCA,这个问题可以转化为rmq问题,求区间的最小值。

    就是首先利用dfs遍历图的所有顶点并且每条边会遍历两次,这样遍历的顶点总共2*n-1个,依次将遍历的边存在数组e[i]中,并且记录每个顶点的深度,

    存入数组level[i]中,我们再开一个数组存每一个顶点首次出现的下标,记录在idx中,这样任意给出两个顶点,我们求出他们对应的下标x,y,然后根据level数组在区间[x,y]中找出深度最小的下标r,这个下标对应的e就是我们要求的节点。这个题目就是将LCA转化为在某段区间中找高度最小的那个顶点。

    代码如下:

    #include <iostream>
    #include
    <stdio.h>
    #include
    <cmath>
    using namespace std;
    const int N=10001;
    bool visit[N];
    struct node{
    int to,next;
    };
    node edge[N];
    int idx[N],e[2*N],adj[N],num=0,n,level[2*N];
    int g_index,m[2*N][15];
    void dfs(int u,int depth)
    {
    int i,v;
    for(i=adj[u];i!=-1;i=edge[i].next)
    {
    v
    =edge[i].to;
    e[g_index]
    =v;
    level[g_index]
    =depth+1;
    // cout<<e[g_index]<<" "<<level[g_index]<<endl;
    if(-1 == idx[v])
    idx[v]
    =g_index;
    g_index
    ++;
    dfs(v,depth
    +1);
    e[g_index]
    =u;
    level[g_index]
    =depth;
    // cout<<e[g_index]<<" "<<level[g_index]<<endl;
    g_index++;
    }

    }
    void initrmq()
    {
    int i,j;
    for(i=0;i<=2*n-1;i++) //写成了i<=n,查了半天
    m[i][0]=i;
    for(j=1;(1<<j)<=2*n-1;j++)
    {
    for(i=1;i+(1<<j)-1<=2*n-1;i++)
    {
    if(level[m[i][j-1]] < level[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 query(int u,int v)
    {
    int x=idx[u];
    int y=idx[v];
    if(x>y)
    {
    int tmp=x;
    x
    =y;
    y
    =tmp;
    }
    int k=(int)((log(1.0*(y-x+1))/log(2.0)));
    int rs=m[x][k];
    if(level[rs]>level[m[y-(1<<k)+1][k]])//一开始写成>,这种错误我都能犯
    rs=m[y-(1<<k)+1][k];
    return e[rs];
    }
    int main()
    {
    int t,i,u,v;
    scanf(
    "%d",&t);
    while(t--)
    {
    memset(adj,
    -1,sizeof(adj));
    memset(level,
    -1,sizeof(level));
    memset(visit,
    false,sizeof(visit));
    memset(idx,
    -1,sizeof(idx));
    memset(m,
    0,sizeof(m));
    num
    =0;
    g_index
    =1;
    scanf(
    "%d",&n);
    for(i=1;i<n;i++)
    {
    scanf(
    "%d%d",&u,&v);
    visit[v]
    =true;
    edge[num].to
    =v;
    edge[num].next
    =adj[u];
    adj[u]
    =num++;
    }
    for(i=1;i<=n;i++)
    {
    if(!visit[i])
    {
    level[g_index]
    =1;
    idx[i]
    =g_index;
    e[g_index]
    =i;
    g_index
    ++;
    dfs(i,
    1);
    }
    }
    initrmq();
    scanf(
    "%d%d",&u,&v);
    printf(
    "%d\n",query(u,v));
    }
    return 0;
    }
  • 相关阅读:
    【杭电】[2016]数据的交换输出
    【杭电】[2015]偶数求和
    【杭电】[2015]偶数求和
    【杭电】[2026]首字母变大写
    【杭电】[2026]首字母变大写
    【杭电】[2075]A|B?
    【杭电】[2075]A|B?
    【杭电】[2043]密码
    【杭电】[2043]密码
    SQL 06: 内连接 (多表查询)
  • 原文地址:https://www.cnblogs.com/buptLizer/p/2179233.html
Copyright © 2011-2022 走看看