• poj1330Nearest Common Ancestors(LCA小结)


    题目请戳这里

    题目大意:意如其名。

    题目分析:本题只有一个查询,所以可以各种乱搞过去。

    不过对于菜鸟而言,还是老老实实练习一下LCA算法。

    LCA有很多经典的算法。按工作方式分在线和离线2种。

    tarjan算法是经典的离线算法。这篇博客讲的太好懂了,我也不好意思班门弄斧,具体戳进去看看就会明白。重点是那个插图,一看秒懂。

    在线算法主要有倍增算法和转RMQ算法。

    另外LCA还有2种更为高效的O(n)-O(1)算法。一种请戳这里,另一种其实就是先将LCA转化成RMQ,再利用笛卡尔树O(n)预处理,O(1)回答,具体可以戳这里

    后两种O(n)算法还没有仔细研究,大致看了下,不是很明白,但是感觉很厉害的样子。mark一下,以后抽时间学习一下。

    下面给出本题的前3种算法具体实现:

    1:tarjan算法(虽然对本题来说有点奢侈了。。)

    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 10005;
    struct node
    {
        int to,next;
    }e[N];
    int head[N],set[N],fa[N],in[N];
    bool vis[N];
    int n,num,p,q;
    void build(int s,int ed)
    {
        e[num].to = ed;
        e[num].next = head[s];
        head[s] = num ++;
    }
    void init()
    {
        num = 0;
        memset(head,-1,sizeof(head));
        memset(in,0,sizeof(in));
    }
    int find(int x)
    {
        int rt = x;
        while(set[rt] != rt)
            rt = set[rt];
        int pa = set[x];
        while(pa != rt)
        {
            set[x] = rt;
            x  = pa;
            pa = set[x];
        }
        return rt;
    }
    void bing(int a,int b)
    {
        int ra = find(a);
        int rb = find(b);
        if(ra != rb)
            set[rb] = ra;
    }
    void dfs(int cur)
    {
        fa[cur] = cur;
        set[cur] = cur;
        int i;
        for(i = head[cur];i != -1;i = e[i].next)
        {
            dfs(e[i].to);
            bing(cur,e[i].to);
            fa[find(cur)] = cur;
        }
        vis[cur] = true;
        if((p == cur && vis[q]))
            printf("%d
    ",fa[find(q)]);
        if((q == cur && vis[p]))
            printf("%d
    ",fa[find(p)]);
    }
    void tarjan()
    {
        int i;
        memset(vis,false,sizeof(vis));
        for(i = 1;i <= n;i ++)
            if(in[i] == 0)
                break;
        dfs(i);
    }
    int main()
    {
        int t;
        int i,a,b;
        scanf("%d",&t);
        while(t --)
        {
            scanf("%d",&n);
            init();
            for(i = 1;i < n;i ++)
            {
                scanf("%d%d",&a,&b);
                build(a,b);
                in[b] ++;
            }
            scanf("%d%d",&p,&q);
            tarjan();
        }
        return 0;
    }


    2:LCA转RMQ,再st算法:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N = 20005;
    
    int dep[N],pos[N],seq[N],first[N],in[N];
    int dp[N][20];
    struct node
    {
        int to,next;
    }e[N];
    int head[N];
    int n,num,p,q,id;
    void build(int s,int ed)
    {
        e[num].to = ed;
        e[num].next = head[s];
        head[s] = num ++;
    }
    
    void dfs(int cur,int deep)
    {
        dep[cur] = deep;
        first[cur] = id;
        pos[id] = cur;
        seq[id ++] = dep[cur];
        int i;
        for(i = head[cur];i != -1;i = e[i].next)
        {
            dfs(e[i].to,deep + 1);
            pos[id] = cur;
            seq[id ++] = dep[cur];
        }
    }
    int rmq()
    {
        int i,j;
        for(i = 1;i <= id;i ++)
            dp[i][0] = i;
        for(j = 1;(1<<j) <= id;j ++)
        {
            for(i = 1;(i + (1<<(j - 1))) <= id;i ++)
                if(seq[dp[i][j - 1]] < seq[dp[i + (1<<(j - 1))][j - 1]])
                    dp[i][j] = dp[i][j - 1];
                else
                    dp[i][j] = dp[i + (1<<(j - 1))][j - 1];
        }
        int tp = first[p];
        int tq = first[q];
        if(tp > tq)
            swap(tp,tq);
        int k = floor(log((double)(tq - tp + 1))/log(2.0));
        int tmp;
        if(seq[dp[tp][k]] < seq[dp[tq - (1<<k) + 1][k]])
            tmp = dp[tp][k];
        else
            tmp = dp[tq - (1<<k) + 1][k];
        return pos[tmp];
    }
    void solve()
    {
        int i;
        id = 1;
        for(i = 1;i <= n;i ++)
            if(in[i] == 0)
                break;
        dfs(i,0);
        id --;
        printf("%d
    ",rmq());
    }
    int main()
    {
        int i,a,b,t;
        freopen("in.txt","r",stdin);
        scanf("%d",&t);
        while(t --)
        {
            scanf("%d",&n);
            num = 0;
            memset(head,-1,sizeof(head));
            memset(in,0,sizeof(in));
            for(i = 1;i < n;i ++)
            {
                scanf("%d%d",&a,&b);
                build(a,b);
                in[b] ++;
            }
            scanf("%d%d",&p,&q);
            solve();
        }
        return 0;
    }


    3:倍增算法:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 10005;
    
    int dp[N][20],deep[N];
    struct node
    {
        int to,next;
    }e[N];
    int n,num,p,q;
    int head[N],in[N];
    void build(int s,int ed)
    {
        e[num].to = ed;
        e[num].next = head[s];
        head[s] = num ++;
    }
    void dfs(int cur,int fa)
    {
        deep[cur] = deep[fa] + 1;
        dp[cur][0] = fa;
        int i;
        for(i = 1;i < 18;i ++)
            dp[cur][i] = dp[dp[cur][i - 1]][i - 1];
        for(i = head[cur];i != -1;i = e[i].next)
        {
            dfs(e[i].to,cur);
        }
    }
    int lca()
    {
        if(deep[p] < deep[q])
            swap(p,q);
        int i,j;
        for(j = deep[p] - deep[q],i = 0;j;j >>= 1,i ++)
        {
            if(j&1)
                p = dp[p][i];
        }
        if(p == q)
            return q;
        for(i = 18;i >= 0;i --)
        {
            if(dp[p][i] != dp[q][i])
            {
                p = dp[p][i];
                q = dp[q][i];
            }
        }
        return dp[q][0];
    }
    void solve()
    {
        int i;
        memset(deep,0,sizeof(deep));
        for(i = 1;i <= n;i ++)
            if(in[i] == 0)
                break;
        dfs(i,0);
        printf("%d
    ",lca());
    }
    int main()
    {
        int t,i,a,b;
        freopen("in.txt","r",stdin);
        scanf("%d",&t);
        while(t --)
        {
            scanf("%d",&n);
            num = 0;
            memset(head,-1,sizeof(head));
            memset(in,0,sizeof(in));
            for(i = 1;i < n;i ++)
            {
                scanf("%d%d",&a,&b);
                build(a,b);
                in[b] ++;
            }
            scanf("%d%d",&p,&q);
            solve();
        }
        return 0;
    }
    


  • 相关阅读:
    Python 五个知识点搞定作用域
    python中的三元表达式(三目运算符)
    Python中 sys.argv的用法简明解释
    pycharm多行批量缩进和反向缩进快捷键
    Python终端如何输出彩色字体
    第8周LeetCode记录
    第7周Leetcode记录
    《Java核心技术》第九章读书笔记(集合)
    《Java核心技术》第八章读书笔记(泛型)
    《Java核心技术》第七章读书笔记(异常处理)
  • 原文地址:https://www.cnblogs.com/pangblog/p/3339615.html
Copyright © 2020-2023  润新知