zoukankan      html  css  js  c++  java
  • LCA tarjan+并查集POJ1470

    LCA tarjan+并查集POJ1470

    https://www.cnblogs.com/JVxie/p/4854719.html

    不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻

    这是个离线算法,现在的粗略理解是输入完毕询问完毕后进行解决的算法

    用了并查集

    1···选取根节点

    2···逐个dfs访问所选节点所有的子节点v

      3···1··对于子节点的dfs访问到头之后

      3···2··标记,进行询问查询

      3···3··如果查询的点访问过,输出其目前祖先

      4···回溯,合并边,更新pre数组(并查集)

    5.所有节点访问完毕,结束

    1.任选一个点为根节点,从根节点开始。

    2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。

    3.若是v还有子节点,返回2,否则下一步。

    4.合并v到u上。

    5.寻找与当前点u有询问关系的点v。

    6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点

    模拟别人打了一下代码

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    using namespace std;
    const int maxn = 1000;
    const int maxm = 1000;
    
    struct node{
        int to,pre;
    }e[maxn * maxn],q[maxn * maxn];
    int pre[maxn];
    bool vis[maxn];
    int id[maxn],cnt;
    int idq[maxn],cntq;
    int in[maxn];
    int ans[maxn];
    int root;
    void init(int n)
    {
        memset(id,-1,sizeof(id));
        memset(idq,-1,sizeof(idq));
        cntq = 0;
        cnt = 0;
        memset(in,0,sizeof(in));
        memset(ans,0,sizeof(ans));
        memset(vis,0,sizeof(vis));
        for(int i = 0;i <= n;i++)
            pre[i] = i;
    }
    void add(int from,int to)
    {
        e[cnt].to = to;
        e[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void addq(int from,int to)
    {
        q[cntq].to = to;
        q[cntq].pre = idq[from];
        idq[from] = cntq++;
    }
    int Find(int x)
    {
        if(pre[x] == x)return x;
        return pre[x] = Find(pre[x]);
    }
    void join(int u,int v)
    {
        int fu = Find(u);
        int fv = Find(v);
        pre[fv] = fu;
    }
    void LCA(int rt)
    {
        for(int i = id[rt];~i;i = e[i].pre)
        {
            int to = e[i].to;
            LCA(to);
            join(rt,to);
        }
        vis[rt] = 1;
        for(int i = idq[rt];~i;i = q[i].pre)
        {
            int que = q[i].to;
            if(vis[que])
                ans[Find(que)]++;
        }
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            init(n);
            int x,y,z;
            for(int i = 0;i < n;i++)
            {
                scanf("%d:(%d)",&x,&y);
                for(int j = 0;j < y;j++)
                {
                    scanf("%d",&z);
                    in[z] = 1;
                    add(x,z);
                }
            }
            int t;
            scanf("%d",&t);
            while(t--)
            {
                while(getchar() !='(');
                scanf("%d%d",&x,&y);
                addq(x,y);
                addq(y,x);
            }
            while(getchar() != ')');
            for(int i = 1;i <= n;i++)
                if(!in[i])root = i;
            LCA(root);
            for(int i = 1;i <= n;i++)
            {
                if(ans[i] != 0)
                    printf("%d:%d
    ",i,ans[i]);
            }
        }
        return 0;
    }
    

     现在我要自己去大一下模板提啦

    http://node2.vjmirror.rainng.com/contest/241642#problem/A

    题意也是模板题意,很简单,错了两个地方都是小失误。。。。

    一个是两个for循环索引都是i

    另一个是空间没开够

    略略略

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    using namespace std;
    const int maxn = 1100;
    int id[maxn],cnt;
    int qid[maxn],qcnt;
    struct node
    {
        int to,pre;
    }e[maxn];
    struct node2
    {
        int to,ID,pre;
    }q[maxn * 3];
    int pre[maxn];
    bool vis[maxn];
    int ans[maxn];
    void init(int n)
    {
        memset(id,-1,sizeof(id));
        memset(qid,-1,sizeof(qid));
        memset(vis,0,sizeof(vis));
        cnt = qcnt = 0;
        for(int i = 0;i <= n;i++)
            pre[i] = i;
    }
    void add(int from,int to)
    {
        e[cnt].to = to;
        e[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void qadd(int from,int to,int I)
    {
        q[qcnt].to = to;
        q[qcnt].pre = qid[from];
        q[qcnt].ID = I;
        qid[from] = qcnt++;
    }
    int Find(int x)
    {
        if(x == pre[x])return x;
        return pre[x] = Find(pre[x]);
    }
    void join(int u,int v)
    {
        int fu = Find(u),fv = Find(v);
        if(fu != fv)
            pre[fv] = fu;
    }
    void tarjan(int rt)
    {
    
        //cout<<"cs"<<" "<<rt<<endl;
        for(int i = id[rt];~i;i = e[i].pre)
        {
            int to = e[i].to;
            tarjan(to);
            join(rt,to);
        }
        vis[rt] = 1;
        for(int i = qid[rt];~i;i = q[i].pre)
        {
            int que = q[i].to;
            if(vis[que])
            {
                ans[q[i].ID] = Find(que);
                //cout<<Find(que)<<endl;
            }
        }
    }
    int main()
    {
        int t,n,m;
        scanf("%d",&t);
        int cas = 1;
        while(t--)
        {
            scanf("%d",&n);
            init(n);
            for(int i = 1;i <= n;i++)
            {
                int n_num,v;
                scanf("%d",&n_num);
                for(int j = 0;j < n_num;++j)
                {
                    scanf("%d",&v);
                    add(i,v);
                }
            }
            scanf("%d",&m);
            int u,v;
            for(int i = 1;i <= m;i++)
            {
                scanf("%d%d",&u,&v);
                qadd(u,v,i);
                qadd(v,u,i);
            }
            tarjan(1);
            printf("Case %d:
    ",cas++);
            for(int i = 1;i <= m;i++)
            {
                printf("%d
    ",ans[i]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    kafka的使用
    linux卸载mysql
    kafka单机版的安装、集群部署 及使用
    winform改变启动界面
    C#连接sqlserver数据库
    叠加dgv中相同的行信息
    重定向和转发
    [Jenkins] 配置任务中的坑s
    【Android】冷门常用 ADB
    Linux 常用环境搭建
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9427228.html
Copyright © 2011-2022 走看看