找出直系亲属
Description
如果A,B是C的父母亲,则A,B是C的parent,C是A,B的child,如果A,B是C的(外)祖父,祖母,则A,B是C的grandparent,C是A,B的grandchild,如果A,B是C的(外)曾祖父,曾祖母,则A,B是C的great-grandparent,C是A,B的great-grandchild,之后再多一辈,则在关系上加一个great-。
Input
输入包含多组测试用例,每组用例首先包含2个整数n(0<=n<=26)和m(0<m<50), 分别表示有n个亲属关系和m个问题, 然后接下来是n行的形式如ABC的字符串,表示A的父母亲分别是B和C,如果A的父母亲信息不全,则用-代替,例如A-C,再然后是m行形式如FA的字符串,表示询问F和A的关系。
当n和m为0时结束输入。
Output
如果询问的2个人是直系亲属,请按题目描述输出2者的关系,如果没有直系关系,请输出-。
具体含义和输出格式参见样例.
Sample Input
3 2
ABC
CDE
EFG
FA
BE
0 0
Sample Output
great-grandparent
-
两种解题方法:
1.深搜(DFS):dp[i][2]数组向上遍历其父母节点
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<list>
#define mod 998244353
#define Max 0x3f3f3f3f
#define Min 0xc0c0c0c0
#define mst(a) memset(a,0,sizeof(a))
#define f(i,a,b) for(int i=a;i<b;i++)
using namespace std;
typedef long long ll;
const int maxn='Z'+1;
char dp[maxn][2]; //dp记录每个节点的父节点和母节点dp[i][0],dp[i][1]
void init(){
for(int i='A';i<maxn;i++){
dp[i][0]='-'; //初始化每个节点的父母节点为-
dp[i][1]='-';
}
}
int dfs(char sx,char ex,int step){
if(sx=='-'){ //某次遍历结束,未找到ex,,则返回int最大值(无父节点:dfs1递归,无母节点:dfs2递归)
return INT_MAX; //int的最大值
}
if(sx==ex){ //遍历找到ex则返回step关系层数
return step;
}
int a,b;
a=dfs(dp[sx][0],ex,step+1); //dfs1,从sx的父节点开始向根遍历,
b=dfs(dp[sx][1],ex,step+1); //dfs2,从sx的母节点开始向根遍历
return min(a,b); //取两次dfs的最小遍历次数,即为关系层数
}
void show(int step,int mark){ //输出结果
if(mark==1){
if(step==1){
cout<<"child"<<endl;
}
else{
while(step>2){
cout<<"great-";
step--;
}
cout<<"grandchild"<<endl;
}
}
else{
if(step==1){
cout<<"parent"<<endl;
}
else{
while(step>2){
cout<<"great-";
step--;
}
cout<<"grandparent"<<endl;
}
}
}
int main(){
ios::sync_with_stdio(false);
int n,m,val,flag;
while(cin>>n>>m){
if(n==0 && m==0){
break;
}
init();
char s1,s2,s3;
for(int i=0;i<n;i++){
cin>>s1>>s2>>s3;
dp[s1][0]=s2;
dp[s1][1]=s3;
}
for(int j=0;j<m;j++){
cin>>s1>>s2;
flag=1;
val=dfs(s1,s2,0); //判断s2是否为s1的父母节点
if(val == INT_MAX){ //s2不是s1的父母节点
flag=0;
val=dfs(s2,s1,0); //则反过来判断s1是否为s2的父母节点
}
if(val == INT_MAX){ //s2与s1无直系亲属关系
cout<<"-"<<endl;
continue;
}
show(val,flag); //s2与s1存在直系亲属关系,打印输出
}
}
return 0;
}
2.并查集:child[i]向下遍历其孩子节点
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<list>
#define mod 998244353
#define Max 0x3f3f3f3f
#define Min 0xc0c0c0c0
#define mst(a) memset(a,0,sizeof(a))
#define f(i,a,b) for(int i=a;i<b;i++)
using namespace std;
typedef long long ll;
using namespace std;
int child[100]; //孩子节点数组
void init(){ //初始化每个节点的孩子节点
for(int i=0;i<100;i++){
child[i]=i;
}
}
int Find(int x,int y){ //关键函数,查找y是否x的孩子节点
while(1){
if(x==y){
return 1;
}
if(x==child[x]){
return 0;
}
x=child[x];
}
}
int main(){
int n,m;
while(cin>>n>>m){
if(n==0&&m==0){
break;
}
init();
while(n--){
char s1,s2,s3;
cin>>s1>>s2>>s3;
if(s2!='-'){
child[s2-'A']=s1-'A'; //保存孩子节点
}
if(s3!='-') {
child[s3-'A']=s1-'A';
}
}
while(m--){
char s1,s2;
cin>>s1>>s2;
int val1=s1-'A',val2=s2-'A';
if(Find(val1,val2)){ //s2为s1的孩子节点
int step=0;
while(val1!=val2){ //遍历
val1=child[val1];
step++; //遍历次数累加为关系层数
}
if(step==1){
cout<<"parent"<<endl;
}
else{
while(step>2){
cout<<"great-";
step--;
}
cout<<"grandparent"<<endl;
}
}
else if(Find(val2,val1)){ //s1为s2的孩子节点
int step=0;
while(val2!=val1){ //遍历
val2=child[val2];
step++; //遍历次数累加为关系层数
}
if(step==1){
cout<<"child"<<endl;
}
else{
while(step>2){
cout<<"great-";
step--;
}
cout<<"grandchild"<<endl;
}
}
else { //s1,s2无直系亲属关系
cout<<'-'<<endl;
}
}
}
return 0;
}