zoukankan      html  css  js  c++  java
  • poj 1330 LCA最近公共祖先

    今天学LCA,先照一个模板学习代码,给一个离线算法,主要方法是并查集加上递归思想。

    再搞,第一个离线算法是比较常用了,基本离线都用这种方法了,复杂度O(n+q)。通过递归思想和并查集来寻找最近公共祖先,自己模拟下过程就可以理解了。

    然后就是在线算法,在线算法方法就很多了,比较常用的是LCA的RMQ转换,然后还有线段树,DP等,最后效率最高的就是倍增法了每次查询O(LogN)

    这道题是离线的。

    给出离线的Tarjan和倍增算法吧。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define MAXN 10001
    int f[MAXN];
    int r[MAXN];
    int indegree[MAXN];
    int vis[MAXN];
    vector<int>hash[MAXN],Qes[MAXN];
    int ancestor[MAXN];
    void init(int n)
    {
        int i;
        for(int i=1;i<=n;i++)
        {
            r[i]=1;
            f[i]=1;
            indegree[i]=0;
            vis[i]=0;
            ancestor[i]=0;
            hash[i].clear();
            Qes[i].clear();
        }
    }
    int find(int n)
    {
        if(f[n]!=n)
            f[n]=find(f[n]);
        return f[n];
    }
    
    int Union(int x,int y)
    {
        int a=find(x);
        int b=find(y);
        if(a==b)
            return 0;
        else if(r[a]<r[b])
        {
            f[a]=b;
            r[b]+=r[a];
        }
        else
        {
            f[b]=a;
            r[a]+=r[b];
        }
        return 1;
    }
    void LCA(int u)
    {
        ancestor[u]=u;
        int size=hash[u].size();
        for(int i=0;i<size;i++)
        {
            LCA(hash[u][i]);
            Union(u,hash[u][i]);
            ancestor[find(u)]=u;
        }
        vis[u]=1;
        size=Qes[u].size();
        for(int i=0;i<size;i++)
        {
            if(vis[Qes[u][i]]==1)
            {
                printf("%d
    ",ancestor[find(Qes[u][i])]);
                return ;
            }
        }
    }
    
    int main()
    {
        int T,s,t,n;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            init(n);
            for(int i=1;i<=n-1;i++)
            {
    
                scanf("%d%d",&s,&t);
                hash[s].push_back(t);
                indegree[t]++;
            }
            scanf("%d%d",&s,&t);
            Qes[s].push_back(t);
            Qes[t].push_back(s);
            for(int j=1;j<=n;j++)
            {
                if(indegree[j]==0)
                {
                    LCA(j);
                    break;
                }
            }
        }
        return 0;
    }
    


     倍增法:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    using namespace std;
    const int N=10002;
    const int Log=20;
    int dp[N][Log],depth[N],deg[N];
    struct Edge
    {
        int to;
        Edge *next;
    }edge[2*N],*cur,*head[N];
    void addedge(int u,int v)
    {
        cur->to=v;
        cur->next=head[u];
        head[u]=cur++;
    }
    void dfs(int u)
    {
        depth[u]=depth[dp[u][0]]+1;
        for(int i=1;i<Log;i++) dp[u][i]=dp[dp[u][i-1]][i-1];
        for(Edge *it=head[u];it;it=it->next)
        {
            dfs(it->to);
        }
    }
    int lca(int u,int v)
    {
        if(depth[u]<depth[v])swap(u,v);
        for(int st=1<<(Log-1),i=Log-1;i>=0;i--,st>>=1)
        {
            if(st<=depth[u]-depth[v])
            {
                u=dp[u][i];
            }
        }
        if(u==v) return u;
        for(int i=Log-1;i>=0;i--)
        {
            if(dp[v][i]!=dp[u][i])
            {
                v=dp[v][i];
                u=dp[u][i];
            }
        }
        return dp[u][0];
    }
    void init(int n)
    {
        for(int i=0;i<=n;i++)
        {
            dp[i][0]=0;
            head[i]=NULL;
            deg[i]=0;
        }
        cur=edge;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n,u,v;
            scanf("%d",&n);
            init(n);
            for(int i=0;i<n-1;i++)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
                deg[v]++;
                dp[v][0]=u;
            }
            for(int i=1;i<=n;i++)
            {
                if(deg[i]==0)
                {
                    dfs(i);
                    break;
                }
            }
            scanf("%d%d",&u,&v);
            printf("%d
    ",lca(u,v));
        }
        return 0;
    }
    
    


     

  • 相关阅读:
    数据类型装换
    变量及数据类型
    27 网络通信协议 udp tcp
    26 socket简单操作
    26 socket简单操作
    14 内置函数 递归 二分法查找
    15 装饰器 开闭原则 代参装饰器 多个装饰器同一函数应用
    12 生成器和生成器函数以及各种推导式
    13 内置函数 匿名函数 eval,exec,compile
    10 函数进阶 动态传参 作用域和名称空间 函数的嵌套 全局变量
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134111.html
Copyright © 2011-2022 走看看