【RMQ&LCA】Nearest Common Ancest…

【RMQ&LCA】Nearest Common Ancestors(最近公共祖先)

Time Limit:1000MS  Memory Limit:65536K
Total Submit:4 Accepted:4

Description

最近公共祖先(lca.pas/c/cpp)

【问题描述】

    有根树是一个在计算机科学和工程学中众所周知的数据结构。如下图所示的例子:


【RMQ&LCA】Nearest <wbr>Common <wbr>Ancestors(最近公共祖先)poj1330 <wbr>pascal <wbr>解题报告



    在上图,每个结点用1-16中的一个整数标记。结点8是这棵树的根。
   一个结点x是一个结点y的祖先当且仅当结点x是在根和结点y的路径上。例如,结点4是结点16的祖先,结点10也是结点16的祖先。实际上,结点8,4和12都是结点16的祖先。记住每个结点都是它自己的祖先。结点8,4,6和7都是结点7的祖先。
    一个结点x被称做结点y和z的公共祖先当且仅当x都是y和z的祖先。因此,结点8 和4是结点16和7的公共祖先。
   一个结点x被称做结点y和z的最近公共祖先当且仅当x是y和z的一个公共祖先且在y和z的所有公共祖先中是最近的。所以,结点16和7的最近公共祖先是结点4,因为结点4比结点8更接近结点16和7。

   在其它例子中,结点2和3的最近公共祖先结点10,结点6和13的最近公共祖先是结点8,结点4和12的最近公共祖先是结点4。在最后的一个例子中,如果y是z的一个祖先,那么y和z的最近公共祖先是y。

    写一个程序找出在一棵树中两个不同结点的最近公共祖先。

Input

输入包括T组数据。第一行是一个整数T。
对每组数据,第一行是一个整数N,表示这棵树的结点数,其中2<=N<=10,000。
这些结点标记为1,2,…,N。
接下来的N-1行包括一对整数,代表一条边,第一个数是第二个数的父亲。
保证N个结点恰好有N-1条边。
最后的一行包括两个不同的整数,表示要求最近公共祖先的两个不同结点

Output

对每组数据输出一行,包括一个表示所求的两个不同结点的最近公共祖先的整数

Sample Input

2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5


Sample Output

4
3

Hint

本题数据不完整,请在本系统测试通过后到http://poj.org/problem?id=1330 提交完整测试!

Source

Taejon 2002

 

这题可以说是下一题的化简版本,下一题要用到ST算法,而这题直接枚举就行了。

具体解题报告请看下一题。

var
 m,n,nf,father,j,l,r:longint;
 f,d:array[0..20001]of longint;
 tree:array[1..10001,0..101]of longint;

procedure init;
var
 i,x,y:longint;
 mark:array[1..10001]of boolean;
begin
 fillchar(mark,sizeof(mark),0);
 fillchar(tree,sizeof(tree),0);
 fillchar(f,sizeof(f),0);
 fillchar(d,sizeof(d),0);
 read(n);
 for i:=1 to n-1 do
  begin
  read(x,y);
  inc(tree[x,0]);
  tree[x,tree[x,0]]:=y;
  mark[y]:=true;
  end;
 read(l,r);
 for i:=1 to n do
  if not mark[i] then
  begin
  father:=i;
  exit;
  end;

end;

procedure dfs(fa,de:longint);
var
 i:longint;
begin
 inc(f[0]);
 f[f[0]]:=fa;
 d[f[0]]:=de;
 for i:=1 to tree[fa,0] do
 begin
  dfs(tree[fa,i],de+1);
 inc(f[0]);
 f[f[0]]:=fa;
 d[f[0]]:=de;
 end;
end;

function min(x,y:longint):longint;
begin
 if x<y then exit(x)
        else exit(y);
end;

procedure main;
var
 i,t,b,ll,rr,minn,mini:longint;
begin
 nf:=2*n-1;
 for i:=1 to nf do
  if f[i]=l then begin ll:=i; break; end;
 for i:=1 to nf do
  if f[i]=r then begin rr:=i; break; end;

 if rr<ll then
  begin
  rr:=rr+ll;
  ll:=rr-ll;
  rr:=rr-ll;
  end;

 minn:=maxlongint;
 for i:=ll to rr do
  if d[i]<minn then begin minn:=d[i]; mini:=i; end;
 writeln(f[mini]);
end;

begin
 read(m);
 for j:=1 to m do
  begin
  init;
  dfs(father,0);
  main;
  end;
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值