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;
    }
    
    


     

  • 相关阅读:
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark RDD(Resilient Distributed Datasets)论文
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    【机器学习实战】第10章 K-Means(K-均值)聚类算法
    [译]flexbox全揭秘
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134111.html
Copyright © 2011-2022 走看看