poj 1470 Closest Common Ancestors

来源:互联网 发布:邓力群 知乎 编辑:程序博客网 时间:2024/05/16 11:36

Description

Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5)

Input

The data set, which is read from a the std input, starts with the tree description, in the form: 

nr_of_vertices 
vertex:(nr_of_successors) successor1 successor2 ... successorn 
...
where vertices are represented as integers from 1 to n ( n <= 900 ). The tree description is followed by a list of pairs of vertices, in the form: 
nr_of_pairs 
(u v) (x y) ... 

The input file contents several data sets (at least one). 
Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.

Output

For each common ancestor the program prints the ancestor and the number of pair for which it is an ancestor. The results are printed on the standard output on separate lines, in to the ascending order of the vertices, in the format: ancestor:times 
For example, for the following tree: 

Sample Input

55:(3) 1 4 21:(0)4:(0)2:(1) 33:(0)6(1 5) (1 4) (4 2)      (2 3)(1 3) (4 3)

Sample Output

2:15:5

Hint

Huge input, scanf is recommended.


#include <stdio.h>
int set[1000],ans[1000];     //set数组用于并查集的操作,ans[i]数组表示i节点是几对数据的最近公共祖先
int depth(int x)
{
    int step=0;
    while(x!=set[x])
    {
        x=set[x];
        step++;
    }
    return step;
}

int main()
{
    int n;                      //n是总节点的个数
    while(scanf("%d",&n)!=EOF)
    {
        int i,j,temp,x,k,ns,a,b,a1,b1;
        for(i=0;i<=n;i++)     //初始化
        { 
            set[i]=i;           //每个节点所在集合的代表节点是自己
            ans[i]=0;         //开始时节点没有祖先
        }
        for(i=0;i<n;i++)
        {
            scanf("%d",&temp);     //temp表示那一小段树的根节点
            while((getchar())!='(');
            scanf("%d",&k);          //k表示它有k个子节点
            while((getchar())!=')');
            for(j=0;j<k;j++)
            {
                scanf("%d",&x);    //输入每个子节点
                set[x]=temp;         //合并操作
            }
        }
        scanf("%d",&ns);        //ns是题中说的nr_of_pairs 
        for(i=0;i<ns;i++)
        {
            while((getchar())!='(');
            scanf("%d%d",&a,&b);
            while((getchar())!=')');
            a1=depth(a);         //计算两个节点的深度,即它到集合中代表节点的距离
            b1=depth(b);
            if(b1>a1)          //b1大说明节点b在树中比节点a深
                for(j=a1;j<b1;j++)    //让b节点往上查找直到与a节点处于同一层
                    b=set[b];
            else                 //否则说明节点a在树中比节点b深
                for(j=b1;j<a1;j++)    //让a节点往上查找直到与b节点处于同一层
                    a=set[a];
            if(a==b)          //当两个节点处于同一层且最近祖先是一个的话
                ans[a]++;    //表示a节点是这对节点的最近公共祖先
            else        //当两个节点处于同一层但是最近祖先不是一个的话
            {
                while(a!=b)     //就不断地往上查找,直到最近公共祖先一样
                {
                    a=set[a];
                    b=set[b];
                }
                ans[a]++;
            }
        }
       for(i=1;i<=n;i++)
        if(ans[i]!=0)
          printf("%d:%d\n",i,ans[i]);
    }
    return 0;
}


0 0
原创粉丝点击