P2814 家谱

【题目描述】

    输入由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系中父亲只有一行,儿子可能有若干行,用#name的形式描写一组父子关系中的父亲的名字,用+name的形式描写一组父子关系中的儿子的名字;接下来用?name的形式表示要求该人的最早的祖先;最后用单独的一个$表示文件结束。

【题目链接】

    https://www.luogu.org/problemnew/show/P2814

【算法】

    1.并查集:用stl,题目难度划分就不靠谱了,然而我傻傻的写了一个string转序号,序号转string的map调了半天,index变量名还不能用。。。然后几乎就是并查集模板。

    2.树的父亲节点表示法:认真想一下发现这道题和并查集关联不大,没必要非要套并查集来做,其实本质上是树的父亲节点表示法,只要知道父亲,然后一路往上追溯就行了,当然可以用map把子节点和父亲连起来,比建树方便。当然并查集也同样是树形结构,其特点在于维护不相交的一系列集合:集合内部的元素相互间存在传递性,同时采用代表元法。

【代码1】

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int tot,p,first=1,tmp;
 4 int fa[50010];
 5 map<string,int> h;
 6 string rec[50010];
 7 string s;
 8 int Get(int x)
 9 {
10     if(fa[x]==x) return x;
11     return fa[x]=Get(fa[x]);
12 }
13 void Merge(int x,int y)
14 {
15     fa[x]=Get(y);
16 }
17 int main()
18 {
19     while(cin>>s&&s[0]!='$') {
20         if(h.find(s.substr(1))==h.end()) h.insert(make_pair(s.substr(1),++tot)),fa[tot]=tot,rec[tot]=s.substr(1);
21         p=h[s.substr(1)];
22         if(s[0]=='#') tmp=h[s.substr(1)];
23         else if(s[0]=='+')
24             Merge(p,tmp);
25         else {
26             if(first) {
27                 for(int i=1;i<=tot;i++) Get(i);
28                 first=0;
29             }
30             cout<<s.substr(1)<<" "<<rec[Get(p)]<<endl;
31         }
32     }
33     return 0;
34 }

【代码2】

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 map<string,string> h;
 4 string s,fa;
 5 string Get(string s)
 6 {
 7     if(h.find(s)==h.end()) return s;
 8     return Get(h[s]);
 9 }
10 int main()
11 {
12     while(cin>>s&&s[0]!='$') {
13         if(s[0]=='#') fa=s.substr(1);
14         else if(s[0]=='+') h.insert(make_pair(s.substr(1),fa));
15         else
16             cout<<s.substr(1)<<" "<<Get(s.substr(1))<<endl;
17     }
18     return 0;
19 }

 

posted @ 2018-08-10 21:30  飞飞翔滴少年  阅读(229)  评论(0编辑  收藏  举报