hihoCoder_#1062_最近公共祖先·一(暴力的并查集??set)

题目链接:https://hihocoder.com/problemset/problem/1062

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢?

“为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边。

“嘿嘿,小Hi,你快过来看!”小Ho招呼道。

“你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一个祖祖祖祖祖爷爷?”

“诶,真是诶……这个网站有点厉害啊。”小Hi不由感叹道。

“是啊,这是什么算法啊,这么厉害!”小Ho也附和道。

“别2,我说的是他能弄到这些数据很厉害,而人类的繁殖树这种层数比较浅的树对这类算法的要求可是简单的不得了,你都能写出来呢!”小Hi道。

“啊?我也能写出来?可是……该从哪开始呢?”小Ho困惑了。

小Ho要面临的问题是这样的,假设现在他知道了N个人的信息——他们的父亲是谁,他需要对于小Hi的每一次提问——两个人的名字,告诉小Hi这两个人的是否存在同一个祖先,如果存在,那么他们的所有共同祖先中辈分最低的一个是谁?

提示:不着急,慢慢来,另外我有一个问题:挖掘机技术哪家强?!

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第1行为一个整数N,意义如前文所述。

每组测试数据的第2~N+1行,每行分别描述一对父子关系,其中第i+1行为两个由大小写字母组成的字符串Father_i, Son_i,分别表示父亲的名字和儿子的名字。

每组测试数据的第N+2行为一个整数M,表示小Hi总共询问的次数。

每组测试数据的第N+3~N+M+2行,每行分别描述一个询问,其中第N+i+2行为两个由大小写字母组成的字符串Name1_i, Name2_i,分别表示小Hi询问中的两个名字。

对于100%的数据,满足N<=10^2,M<=10^2, 且数据中所有涉及的人物中不存在两个名字相同的人(即姓名唯一的确定了一个人)。

输出

对于每组测试数据,对于每个小Hi的询问,输出一行,表示查询的结果:如果根据已知信息,可以判定询问中的两个人存在共同的祖先,则输出他们的所有共同祖先中辈分最低的一个人的名字,否则输出-1。

样例输入

11
JiaYan JiaDaihua
JiaDaihua JiaFu
JiaDaihua JiaJing
JiaJing JiaZhen
JiaZhen JiaRong
JiaYuan JiaDaishan
JiaDaishan JiaShe
JiaDaishan JiaZheng
JiaShe JiaLian
JiaZheng JiaZhu
JiaZheng JiaBaoyu
3
JiaBaoyu JiaLian
JiaBaoyu JiaZheng
JiaBaoyu LinDaiyu

样例输出

JiaDaishan
JiaZheng
-1

题意很明确,一开始看的类似一个树,然后两个节点一直向根节点回溯,开个string类型的map记录他们的父节点,构成一颗树(类似并查集);

然后动手实现的时候一开始想着将他们按层次分号,谁在后面谁向上查,但是发现非常不好实现,后来发现数据量并不大,可以直接先找出一个人的所有祖先,然后,另一个人对这个人的所有祖先进行查找,第一个找到的必定是第一个公共祖先(显而易见)

注意!如果输入的两个族谱之外的同一个人,则输出那个人的名字!(WA了几发才找出来)

于是就用个存string的容器set存name1的所有祖先,然后name2向上一直找就行了,注意一下如果是两个相同的人名的话直接就可以输出了,不用查找(后来发现。。。去掉也对。。)

ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
#include<map>   
#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<fstream>
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);
const int MAXN=1e5+10;
const int INF=0x3f3f3f3f;
const ll mod=1e9+7;

map<string,string> mp;
int pre[MAXN];
int ecnt;
int n,m;

void intt()
{
	mp.clear();
}

int main()
{
	std::ios::sync_with_stdio(false);
	cin>>n;
	intt();
	string name1,name2;
	for(int i=1;i<=n;++i)
	{
		cin>>name1>>name2;
		mp[name2]=name1;
	}
	cin>>m;
	for(int i=1;i<=m;++i)
	{
		cin>>name1>>name2;
//		if(name1==name2)//额。。似乎去掉也对。。。
//		{
//			cout<<name1<<endl;
//			continue;
//		}
		set<string> n1;
		while(1)
		{
			n1.insert(name1);
			if(mp[name1]=="")
				break;
			name1=mp[name1];
		}
		while(1)
		{
			if(n1.find(name2)!=n1.end())
			{
				cout<<name2<<endl;
				break;
			}
			if(mp[name2]!="")
				name2=mp[name2];
			else
			{
				cout<<-1<<endl;
				break;
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/82382140
今日推荐