zoukankan      html  css  js  c++  java
  • poj 1330 Nearest Common Ancestors(LCA:最近公共祖先)

    多校第七场考了一道lca,那么就挑一道水题学习一下吧= =

    最简单暴力的方法:建好树后,输入询问的点u,v,先把u全部的祖先标记掉,然后沿着v->rt(根)的顺序检查,第一个被u标记的点即为u,v的公共祖先。

    标记的时候又犯老毛病了:while,do while都不对,最后还是while(1)了T^T

     1 #include<cstdio>
     2 #include<cstring>
     3 
     4 const int MAXN=11111;
     5 
     6 int p[MAXN],vis[MAXN];
     7 
     8 int main()
     9 {
    10     int T,n,u,v;
    11     scanf("%d",&T);
    12     while(T--)
    13     {
    14         scanf("%d",&n);
    15         memset(vis,0,sizeof(vis));
    16         memset(p,-1,sizeof(p));
    17         for(int i=0;i<n-1;i++){
    18             scanf("%d%d",&u,&v);
    19             p[v]=u;
    20         }
    21         scanf("%d%d",&u,&v);
    22         while(1)
    23         {
    24             vis[u]=1;
    25             if(p[u]==-1)
    26                 break;
    27             u=p[u];
    28         }
    29         while(vis[v]!=1)
    30             v=p[v];
    31         printf("%d
    ",v);
    32     }
    33     return 0;
    34 }
    35 /*
    36 10
    37 3
    38 1 2
    39 1 3
    40 2 3
    41 */
    View Code

    然后是tarjin了:

    自己先照着推了一遍代码,才把图示给看明白:http://www.csie.ntnu.edu.tw/~u91029/LowestCommonAncestor.html

    可以处理多组询问

    因为是以dfs为框架,所以先处理子树,依次将当前点u的每棵子树加入当前点的集合,之后对当前点进行询问(u,v)。若v已被标记,由于是dfs,所以最近公共祖先包含v的子树必然已经完成了搜索,那么v所在集合的祖先 find(v) 就是询问(u,v)的解。又因为是dfs,所以子树内的询问必然已经完成。

    注意:询问(u,v)要正反向各加一遍,因为标记vis有先后顺序,而我们不清楚u,v的被访问的顺序。搜索到u时v尚未被标记,会放弃此次询问。所以不必担心同一次询问被完成了两次,其中一次会被舍弃。

    关键是要理解先处理dfs,再合并集合。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<vector>
      4 #define clr(a,m) memset(a,m,sizeof(a))
      5 #define rep(i,a,b) for(int i=a;i<=b;i++)
      6 using namespace std;
      7 
      8 const int MAXN=11111;
      9 
     10 struct Edge{
     11     int v,next;
     12     Edge(){}
     13     Edge(int _v,int _next):v(_v),next(_next){}
     14 }edge[MAXN<<1];
     15 
     16 vector<int>query[MAXN];
     17 
     18 int p[MAXN],vis[MAXN],ancestor[MAXN];
     19 int head[MAXN],tol;
     20 
     21 void init(int n)
     22 {
     23     tol=0;
     24     clr(head,-1);
     25 
     26     rep(i,1,n){
     27         query[i].clear();
     28     }
     29 }
     30 
     31 void add(int u,int v)
     32 {
     33     edge[tol]=Edge(v,head[u]);
     34     head[u]=tol++;
     35 }
     36 
     37 int build(int n)
     38 {
     39     int u,v;
     40     init(n);
     41     clr(vis,0);
     42     rep(i,1,n-1){
     43         scanf("%d%d",&u,&v);
     44         vis[v]=1;
     45         add(u,v);
     46     }
     47     rep(i,0,0){
     48         scanf("%d%d",&u,&v);
     49         query[u].push_back(v);
     50         query[v].push_back(u);
     51     }
     52     rep(i,1,n)
     53         if(!vis[i])
     54             return i;
     55 }
     56 
     57 int find(int x)
     58 {
     59     return (x==p[x])?x:(p[x]=find(p[x]));
     60 }
     61 
     62 void dfs(int x)
     63 {
     64     vis[x]=1;
     65     for(int i=head[x];i!=-1;i=edge[i].next)
     66     {
     67         int v=edge[i].v;
     68         dfs(v);
     69         p[v]=x;
     70     }
     71     
     72     int siz =query[x].size()-1;
     73     rep(i,0,siz)
     74     {
     75         if(vis[query[x][i]]){
     76             printf("%d
    ",find(query[x][i]));
     77             return ;
     78         }
     79     }
     80 }
     81 
     82 void LCA(int rt,int n)
     83 {
     84     clr(vis,0);
     85     rep(i,1,n)
     86         p[i]=i;
     87     dfs(rt);
     88 }
     89 
     90 int main()
     91 {
     92     int T,n,u,v;
     93     scanf("%d",&T);
     94     while(T--)
     95     {
     96         scanf("%d",&n);
     97         int rt=build(n);
     98         LCA(rt,n);
     99     }
    100     return 0;
    101 }
    View Code

    有一点要注意的:query[x].size()的返回值竟然不是 int 型的= = ,不信可以把 siz 省略掉,在循环内打印一下,惊喜的发现 for(int i=0;i<-1;i++) 这种东西竟然能够进入循环。强制转换(int)也能解决。

    再附上一段代码,是实现全部询问的,当然不适合这道题,MAXN=11111,MLE我竟然还反应了半天。。

     1 void dfs(int x,int n)
     2 {
     3     vis[x]=1;
     4     for(int y=head[x];y!=-1;y=edge[y].next)
     5     {
     6         int v=edge[y].v;
     7         dfs(v,n);
     8         p[v]=x;
     9     }
    10     rep(y,1,n)
    11         if(vis[y])
    12             lca[x][y]=lca[y][x]=find(y);
    13 }
    View Code
  • 相关阅读:
    vmware下玩ubuntu总结
    .Net Json 字典序列化
    Flex Air TitleWindow 拖动范围控制
    TimesTen 问题荟萃
    TimesTen 时间戳(timestamp)用法
    批量数据插入 (.Net, ODBC)
    腾讯 360浏览器 调用js问题
    [转]Android项目源码混淆问题解决方法
    Intent调用大全
    View实现涂鸦、撤销以及重做功能【转】
  • 原文地址:https://www.cnblogs.com/zstu-abc/p/3257604.html
Copyright © 2011-2022 走看看