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


     

  • 相关阅读:
    深入浅出:了解前后端分离优势、前后端接口联调以及优化问题
    深入浅出:了解JavaScript中的call,apply,bind的差别
    Vue2.0 搭建Vue脚手架(vue-cli)
    深入浅出:promise的各种用法
    深入浅出:了解常见的设计模式(闭包、垃圾回收机制)
    sql server xml 功能
    sqlite 用法
    PowerDesigner使用
    asp.net 开发注意的几点
    vue template
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134111.html
Copyright © 2011-2022 走看看