L2-016 愿天下有情人都是失散多年的兄妹 (25 分) 搜索,结构体应用

呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

输入格式:
输入第一行给出一个正整数N(2 ≤ N ≤10
4
),随后N行,每行按以下格式给出一个人的信息:

本人ID 性别 父亲ID 母亲ID
其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1。

接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

输出格式:
对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind;如果是异性并且关系出了五服,输出Yes;如果异性关系未出五服,输出No。

输入样例:
24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011
输出样例:
Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No

更新:有个问题,五服以内是指最近公共祖先相对于两个人都是五服以内还是,只是有一个人五服以内就算。。答案是:只要一个人是五服以内就算,那就需要搜索不止5层,而是要搜完,但是这题呢保证了两个人是同辈,所以两人到最近公共祖先的距离是一样的,所以可以只搜索五层,也可以全搜,全搜的话需要标记搜索节点的代数,以便判断是多少服

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1000005;
int n,k;
int f[N],m[N],g[N];
int st[N],flag;

void dfs(int x,int t)
{
	if(st[x]>0&&t<=5||st[x]>0&&st[x]<=5){
		flag=true; return ;
	}
	st[x]=t;
	if(f[x]!=-1)dfs(f[x],t+1);
	if(m[x]!=-1)dfs(m[x],t+1);
}
int main()
{
	cin>>n;
	memset(f,-1,sizeof f);
	memset(m,-1,sizeof m);
	for(int i=0;i<n;++i)
	{
		int x,y,z;char c;cin>>x>>c>>y>>z;
		f[x]=y;
		m[x]=z;
		g[x]=c;
		if(y!=-1)g[y]='M';
		if(z!=-1)g[z]='F';
	}
	cin>>k;
	while(k--)
	{
		int x,y;cin>>x>>y;
		if(g[x]==g[y])cout<<"Never Mind"<<endl;
		else {
			memset(st,0,sizeof st);
			flag=false;
			dfs(x,1);dfs(y,1);
			if(flag)cout<<"No"<<endl;
			else cout<<"Yes"<<endl;
		}
	}
	return 0;
}
和冰岛人的区别:冰岛人只看父亲,可以通过循环来迭代判断,而这题要同时考虑父亲和母亲两个方向,因此必须要通过搜索来实现,从两个人分别搜索一遍,上限为5代,如果有重合的,那么就说明五服以内

由于对每个人,只需要知道他的父亲和母亲,即每个结点的出边是固定两条,且N<1e5,因此不需要邻接表,只需要一个结构体来数组来存储即可,或者多个int数组来分别存储父、母和性别

解法一:数组存关系

#include <bits/stdc++.h>
using namespace std;
const int N=100005; 
int n,k,f[N],m[N],x,a,b,v[N];
char c,gender[N];
bool flag;
void dfs(int u,int t){
	if(t>=6)return;
	if(v[u]){
		flag=false;return;
	}	
	v[u]=1;
	if(f[u]!=-1)dfs(f[u],t+1);
	if(m[u]!=-1)dfs(m[u],t+1);
} 
int main(){
	cin>>n;
	memset(f,-1,sizeof f);memset(m,-1,sizeof m);
	for(int i=0;i<n;++i){
		cin>>x>>c>>a>>b;
		f[x]=a;m[x]=b;gender[x]=c;gender[a]='M';gender[b]='F';
	}
	cin>>k;
	while(k--){
		cin>>a>>b;
		if(gender[a]==gender[b])cout<<"Never Mind"<<endl;
		else {
			flag=true;
			memset(v,0,sizeof v);
			dfs(a,1);dfs(b,1);
			if(flag)cout<<"Yes"<<endl;else cout<<"No"<<endl;
		}
	}
	return 0;
}

解法二:结构体数组存关系

#include <bits/stdc++.h>

using namespace std;

const int N=100005;

class node
{
	public:
		char sex='N';
		int f=-1;
		int m=-1;
};
node ns[N];
int n,m,v[N];
bool flag;

void dfs(int u,int t)
{
	if(t>=6)return;
	if(u==-1)return;
	if(v[u]==1){
		flag=true;return;
	}
	v[u]=1;
	dfs(ns[u].f,t+1);
	dfs(ns[u].m,t+1);
}

int main()
{
	cin>>n;
	while(n--)
	{
		int a,c,d;char b;
		cin>>a>>b>>c>>d;
		ns[a].sex=b;
		ns[a].f=c;
		ns[a].m=d;
		
		ns[c].sex='M';
		ns[d].sex='F';
	}
	cin>>m;
	while(m--)
	{
		int x,y;cin>>x>>y;
		if(ns[x].sex==ns[y].sex)cout<<"Never Mind"<<endl;
		else 
		{
			flag=false;
			memset(v,0,sizeof v);
			dfs(x,1);dfs(y,1);
			if(flag)cout<<"No"<<endl;
			else cout<<"Yes"<<endl;
		}	
	}
	return 0;
}
posted @ 2022-11-17 23:03  林动  阅读(36)  评论(0编辑  收藏  举报