Description
现代的人对于本家族血统越来越感兴趣, 现在给出充足的父子关系, 请你编写程序找到 某个人的最早的祖先。
Input
输入文件由多行组成, 首先是一系列有关父子关系的描述, 其中每一组父子关系由二行 组成,用#name 的形式描写一组父子关系中的父亲的名字,用+name 的形式描写一组父子关 系中的儿子的名字;接下来用?name 的形式表示要求该人的最早的祖先;最后用单独的一个 $表示文件结束。规定每个人的名字都有且只有 6 个字符,而且首字母大写,且没有任意两 个人的名字相同。最多可能有 1000 组父子关系,总人数最多可能达到 50000 人,家谱中的 记载不超过 30 代。
Output
按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式:本人的名字+一个 空格+祖先的名字+回车。
Sample Input
#George
+Rodney
#Arthur
+Gareth
+Walter
#Gareth
+Edward
?Edward
?Walter
?Rodney
?Arthur
$
Sample Output
Edward Arthur
Walter Arthur
Rodney George
Arthur Arthur
一看这题,只需求最早的祖先,那么我们可以把有父子关系的一对和并即可。如果A是B的祖先,P[x]为x的祖先,那么P[B]=A。
(自己好好想想吧,如果不会并查集的,在网上看看)。
我们可以把每个人编号。用HASH表快速找出一个人前面有没有出现过即可。
标程:
• const
• p1=150000;
• var
• h:array [0..p1] of string;{HASH表,记录名字}
• h1:array [0..p1] of longint; {HASH表,记录编号}
• f:array [1..60000] of string; {每个编号对应的名字}
• p:array [1..60000] of longint; {并查集}
• s:string;
• ch:char;
• x,y,k,i:longint;
• function hash(s:string):longint;
• var
• i:longint;
• begin
• hash:=0;
• for i:=1 to length(s) do
• hash:=hash*4+ord(s[i]);
• {哈希函数,这玩意贼神奇,一开始不乘4,超时!
• 乘个3,极限过!乘了4,直接15MS!!!!}
• end;
•
• function fd(s:string):longint;{查找}
• var x:longint;
• begin
• x:=hash(s);
• while h[x]<>'' do
• begin
• if h[x]=s then exit(h1[x]);{找到退出编号}
• inc(x);
• if x>p1 then x:=0;
• end;
• exit(0); {找不到退出0}
• end;
•
• procedure ins(s:string;a:longint);{插入}
• var i,x:longint;
• begin
• x:=hash(s);
• while h[x]<>'' do
• begin
• inc(x);
• if x>p1 then x:=0;
• end;
• h[x]:=s; h1[x]:=a; {找到空位x后记录数据}
• end;
•
• function find(x:longint):longint;{并查集+路径压缩}
• var y,root,w:longint;
• begin
• y:=x;
• while p[y]>0 do
• y:=p[y];
• root:=y;
• y:=x;
• while p[y]>0 do
• begin
• w:=p[y];
• p[y]:=root;
• y:=w;
• end;
• find:=root;
• end;
•
• procedure union(x,y:longint);{合并,x是父亲,y是儿子}
• var
• u,v:longint;
• begin
• u:=find(x);
• v:=find(y);
• p[v]:=u; {把儿子的祖先接到y上}
• end;
•
• begin
• for i:=1 to p1 do
• begin h[i]:=''; h1[i]:=0; end;
• repeat
• readln(s);
• if s='$' then break;
• ch:=s[1]; delete(s,1,1); {s删掉第一个字符是人名}
• x:=fd(s); {查找}
• if x=0 then {找不到给当前人编号,并插入HASH表}
• begin inc(k); f[k]:=s; x:=k; ins(s,k); end;
• if ch='#' then
• y:=x; {记录父亲的编号}
• if ch='+' then
• union(y,x); {合并父亲和儿子}
• if ch='?' then
• begin
• writeln(s,' ',f[find(x)]);{查找x的最早的祖先,输出其姓名}
• end;
• until 1=2;
• end.
•
家谱(并查集)
最新推荐文章于 2024-07-30 09:25:05 发布