并查集 信息奥赛一本通 家谱(gen)

家谱(gen)


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 227     通过数: 109 

【题目描述】

现代的人对于本家族血统越来越感兴趣,现在给出充足的父子关系,请你编写程序找到某个人的最早的祖先。

【输入】

由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系由二行组成,用#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<bits/stdc++.h>
using namespace std;
#define N 50100
string b[N],s1,s2;//b[i]表示编号i的名字
  char ch;//在主函数定义就运行错误,不知道为啥
int fa[N],sum=0;
//fa[i]保存i所在家族的最老祖先
int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
int w(string s)  //将字符串转换并查集中唯一序号
{
    for(int i=1;i<=sum;i++)  //防止重复
        if(b[i]==s) return i;
    b[++sum]=s;
    return sum;
}
int main()
{
   cout<<ch<<endl;
   for(int i=1;i<=N;i++)
    fa[i]=i;
   do
   {
       cin>>ch;
       switch(ch)
       {
       case'#':
        cin>>s1;break;
       case'+':
           cin>>s2;
           if(s1!=s2)
            fa[find(w(s2))]=find(w(s1));//利用并查集合并最早的祖先
             break;
        case'?':
            cin>>s2;
         cout<<s2<<" "<<b[find(w(s2))]<<endl;
         break;
       }
   }while(ch!='$');
   return 0;
}




猜你喜欢

转载自blog.csdn.net/sdz20172133/article/details/80192408
今日推荐