【题目描述】
现代的人对于本家族血统越来越感兴趣,现在给出充足的父子关系,请你编写程序找到某个人的最早的祖先。
【输入】
由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系由二行组成,用#name的形式描写一组父子关系中的父亲的名字,用+name的形式描写一组父子关系中的儿子的名字;接下来用?name的形式表示要求该人的最早的祖先;最后用单独的一个$表示文件结束。规定每个人的名字都有且只有6个字符,而且首字母大写,且没有任意两个人的名字相同。最多可能有1000组父子关系,总人数最多可能达到50000人,家谱中的记载不超过30代。
【输出】
按照输入的要求顺序,求出每一个要找祖先的人的祖先,格式:本人的名字+一个空格+祖先的名字+回车。
【输入样例】
#George +Rodney #Arthur +Gareth +Walter #Gareth +Edward ?Edward ?Walter ?Rodney ?Arthur $
【输出样例】
Edward Arthur Walter Arthur Rodney George Arthur Arthur
字符串形式的并查集
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
map<string,int>name; //名字对应下标
map<int,string>num; //下标对应名字
map<string,bool>b; //是否访问过
int f[50005]; //并查集数组
string s,ss;
int i,j,k,len,father;
bool pd=false;
int find(int x)
{
if (f[x]==x)
return f[x];
f[x]=find(f[x]);
return f[x];
}
void merge(int x,int y) //并查集连接
{
int f1=find(x);
int f2=find(y);
f[f1]=f2;
return;
}
int main()
{
for (i=1; i<=50000; ++i) //并查集初始化
f[i]=i;
i=0;
while (cin>>s)
{
if (s=="$")
break;
if (s[0]=='#'||s[0]=='+')
{
len=s.length();
ss=s.substr(1,len-1);
if (!b[ss]) //以前没出现过
{
i++;
name[ss]=i;
b[ss]=true;
num[i]=ss;
if (s[0]=='#')
father=i;
if (s[0]=='+')
merge(i,father);
}
else //出现过
{
if (s[0]=='#')
father=name[ss];
if (s[0]=='+')
merge(name[ss],father);
}
}
if (s[0]=='?')
{
if(pd==false)
for (j=1; j<=i; ++j)
k=find(j);
pd=true;
len=s.length();
ss=s.substr(1,len-1);
cout<<ss;
cout<<" ";
cout<<num[f[name[ss]]]<<endl;
}
}
return 0;
}