poj1330Nearest Common Ancestors(LCA小结)

来源:互联网 发布:mac卡住怎么办 编辑:程序博客网 时间:2024/06/06 08:33

题目请戳这里

题目大意:意如其名。

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

不过对于菜鸟而言,还是老老实实练习一下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\n",fa[find(q)]);    if((q == cur && vis[p]))        printf("%d\n",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\n",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\n",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;}


原创粉丝点击