zoukankan      html  css  js  c++  java
  • LCA

    POJ - 1330 Nearest Common Ancestors(dfs+ST在线算法|LCA倍增法)

    d.输入树中的节点数N,输入树中的N-1条边。最后输入2个点,输出它们的最近公共祖先。

    s.裸的最近公共祖先。

    c.dfs+ST在线算法:

    /*
    LCA(POJ 1330)
    在线算法 DFS+ST
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    const int MAXN=10010;
    int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列
    struct ST{
        int mm[2*MAXN];
        int dp[2*MAXN][20];//最小值对应的下标
        void init(int n){
            mm[0]=-1;
            for(int i=1;i<=n;i++){
                mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
                dp[i][0]=i;
            }
            for(int j=1;j<=mm[n];j++)
                for(int i=1;i+(1<<j)-1<=n;i++)
                dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
        //查询[a,b]之间最小值的下标
        int query(int a,int b){
            if(a>b)swap(a,b);
            int k=mm[b-a+1];
            return rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
        }
    };
    //边的结构体定义
    struct Edge{
        int to,next;
    };
    Edge edge[MAXN*2];
    int tot,head[MAXN];
    
    int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
    int P[MAXN];//P[i]表示点i在F中第一次出现的位置
    int cnt;
    ST st;
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    //加边,无向边需要加两次
    void addedge(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void dfs(int u,int pre,int dep){
        F[++cnt]=u;
        rmq[cnt]=dep;
        P[u]=cnt;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v==pre)continue;
            dfs(v,u,dep+1);
            F[++cnt]=u;
            rmq[cnt]=dep;
        }
    }
    //查询LCA前的初始化
    void LCA_init(int root,int node_num){
        cnt=0;
        dfs(root,root,0);
        st.init(2*node_num-1);
    }
    //查询u,v的lca编号
    int query_lca(int u,int v){
        return F[st.query(P[u],P[v])];
    }
    bool flag[MAXN];
    int main(){
        int T;
        int N;
        int u,v;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&N);
            init();
            memset(flag,false,sizeof(flag));
            for(int i=1;i<N;i++){
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
                flag[v]=true;
            }
            int root;
            for(int i=1;i<=N;i++)
                if(!flag[i]){
                    root=i;
                    break;
                }
            LCA_init(root,N);
            scanf("%d%d",&u,&v);
            printf("%d
    ",query_lca(u,v));
        }
        return 0;
    }
    View Code

    c2.LCA倍增法:

    /*
    POJ 1330
    LCA在线算法
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    
    const int MAXN=10010;
    const int DEG=20;
    
    struct Edge{
        int to,next;
    }edge[MAXN*2];
    int head[MAXN],tot;
    void addedge(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
    }
    int fa[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先
    int deg[MAXN];//深度数组
    
    void BFS(int root){
        queue<int>que;
        deg[root]=0;
        fa[root][0]=root;
        que.push(root);
        while(!que.empty()){
            int tmp=que.front();
            que.pop();
            for(int i=1;i<DEG;i++)
                fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
            for(int i=head[tmp];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                if(v==fa[tmp][0])continue;
                deg[v]=deg[tmp]+1;
                fa[v][0]=tmp;
                que.push(v);
            }
        }
    }
    int LCA(int u,int v){
        if(deg[u]>deg[v])swap(u,v);
        int hu=deg[u],hv=deg[v];
        int tu=u,tv=v;
        for(int det=hv-hu,i=0;det;det>>=1,i++)
            if(det&1)
                tv=fa[tv][i];
        if(tu==tv)return tu;
        for(int i=DEG-1;i>=0;i--){
            if(fa[tu][i]==fa[tv][i])
                continue;
            tu=fa[tu][i];
            tv=fa[tv][i];
        }
        return fa[tu][0];
    }
    bool flag[MAXN];
    int main(){
        int T;
        int n;
        int u,v;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            init();
            memset(flag,false,sizeof(flag));
            for(int i=1;i<n;i++){
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
                flag[v]=true;
            }
            int root;
            for(int i=1;i<=n;i++)
                if(!flag[i]){
                    root=i;
                    break;
                }
            BFS(root);
            scanf("%d%d",&u,&v);
            printf("%d
    ",LCA(u,v));
        }
        return 0;
    }
    View Code

    POJ - 1470 Closest Common Ancestors(离线Tarjan算法)

    d.输出测试用例中是最近公共祖先的节点,以及这个节点作为最近公共祖先的次数。

    s.最近公共祖先,离线Tarjan算法

    c.离线Tarjan算法

    /*
    POJ 1470
    给出一颗有向树,Q个查询
    输出查询结果中每个点出现次数
    */
    /*
    离线算法,LCATarjan
    复杂度O(n+Q);
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    
    const int MAXN=1010;
    const int MAXQ=500010;//查询数的最大值
    
    //并查集部分
    int F[MAXN];//需要初始化为-1
    int find(int x){
        if(F[x]==-1)return x;
        return F[x]=find(F[x]);
    }
    void bing(int u,int v){
        int t1=find(u);
        int t2=find(v);
        if(t1!=t2)
            F[t1]=t2;
    }
    //***********************
    bool vis[MAXN];//访问标记
    int ancestor[MAXN];//祖先
    struct Edge{
        int to,next;
    }edge[MAXN*2];
    int head[MAXN],tot;
    void addedge(int u,int v){
        edge[tot].to=v;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    
    struct Query{
        int q,next;
        int index;//查询编号
    }query[MAXQ*2];
    int answer[MAXQ];//存储最后的查询结果,下标0 Q-1
    int h[MAXQ];
    int tt;
    int Q;
    
    void add_query(int u,int v,int index){
        query[tt].q=v;
        query[tt].next=h[u];
        query[tt].index=index;
        h[u]=tt++;
        query[tt].q=u;
        query[tt].next=h[v];
        query[tt].index=index;
        h[v]=tt++;
    }
    
    void init(){
        tot=0;
        memset(head,-1,sizeof(head));
        tt=0;
        memset(h,-1,sizeof(h));
        memset(vis,false,sizeof(vis));
        memset(F,-1,sizeof(F));
        memset(ancestor,0,sizeof(ancestor));
    }
    void LCA(int u){
        ancestor[u]=u;
        vis[u]=true;
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(vis[v])continue;
            LCA(v);
            bing(u,v);
            ancestor[find(u)]=u;
        }
        for(int i=h[u];i!=-1;i=query[i].next){
            int v=query[i].q;
            if(vis[v]){
                answer[query[i].index]=ancestor[find(v)];
            }
        }
    }
    bool flag[MAXN];
    int Count_num[MAXN];
    int main(){
        int n;
        int u,v,k;
        while(scanf("%d",&n)==1){
            init();
            memset(flag,false,sizeof(flag));
            for(int i=1;i<=n;i++){
                scanf("%d:(%d)",&u,&k);
                while(k--){
                    scanf("%d",&v);
                    flag[v]=true;
                    addedge(u,v);
                    addedge(v,u);
                }
            }
            scanf("%d",&Q);
            for(int i=0;i<Q;i++){
                char ch;
                cin>>ch;
                scanf("%d %d)",&u,&v);
                add_query(u,v,i);
            }
            int root;
            for(int i=1;i<=n;i++)
                if(!flag[i]){
                    root=i;
                    break;
                }
            LCA(root);
            memset(Count_num,0,sizeof(Count_num));
            for(int i=0;i<Q;i++)
                Count_num[answer[i]]++;
            for(int i=1;i<=n;i++)
                if(Count_num[i]>0)
                    printf("%d:%d
    ",i,Count_num[i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    二分练习题4 查找最接近的元素 题解
    二分练习题5 二分法求函数的零点 题解
    二分练习题3 查找小于x的最大元素 题解
    二分练习题2 查找大于等于x的最小元素 题解
    二分练习题1 查找元素 题解
    code forces 1176 D. Recover it!
    code forces 1173 B. Nauuo and Chess
    code forces 1173 C. Nauuo and Cards
    吴恩达深度学习课程笔记-15
    吴恩达深度学习课程笔记-14
  • 原文地址:https://www.cnblogs.com/gongpixin/p/5367102.html
Copyright © 2011-2022 走看看