(纪中)2409. Cow Evolution【STL】

(File IO): input:evolution.in output:evolution.out
时间限制: 1000 ms 空间限制: 262144 KB 具体限制
Goto ProblemSet


题目描述
现在是 3019 3019 3019年,在过去的一千年里发生了不计其数的牛类进化,产生了具有各种有趣特性的奶牛。
牛类进化的记录可以用一棵树来表示,起源是位于树根位置的没有特殊特性的奶牛。树上每一个产生后代的结点,有可能所有的奶牛都进化出了一种新的特性(比如说喷火( f i r e b r e a t h i n g fire breathing firebreathing),如下图所示,其中所有斑点( s p o t s spots spots)奶牛最后都能喷火),或者是奶牛种群产生了分支进化,其中有些进化出了新的特性(比如,飞( f l y i n g flying flying)),有的没有。

树底部的叶结点表示 3019 3019 3019年所有产生的奶牛的子种群。没有不同的叶结点(子种群)具有完全相同的一组特性。例如,子种群#1是没有特殊特性的奶牛,子种群#3是能够心灵感应的( t e l e p a t h i c telepathic telepathic)并且会飞的奶牛。相比之下,子种群#2是会飞但不能心灵感应的奶牛。子种群#3是唯一既会飞又会心灵感应的。
像上图这样每一种进化出的新特性都恰好在树中的一条边上产生(也就是说,在整个进化历史中仅在一个时间点产生),这样的进化树被称为是“合法的”。例如,如果斑点这一特性在两个不同分支中均进化产生,这棵进化树就不是合法的。给定 3019 3019 3019年奶牛子种群的描述,请判断是否这可以由一棵合法的进化树所解释。


输入
输入的第一行包含子种群的数量 N ( 2 ≤ N ≤ 25 ) N(2≤N≤25) N2N25。以下N行每行描述一个子种群。每行包含一个整数 K ( 0 ≤ K ≤ 25 ) K(0≤K≤25) K0K25,之后是K个该子种群奶牛所拥有的特性。特性是由至多 20 20 20个小写字母 ( a . . z ) (a..z) a..z组成的字符串。没有两个子种群拥有完全相同的特性。

输出
如果可能构造一棵可以解释所有子种群产生途径的进化树,输出 " y e s " "yes" "yes",否则输出 " n o " "no" "no"


样例输入
4
2 spots firebreathing
0
1 flying
2 telepathic flying

样例输出
yes


数据范围限制


解题思路
首先感谢 H   J H~J H J巨老的详细讲解,我才 A C AC AC了这题。。
对于一个子树 T T T,我们设他的儿子为 T i T_i Ti,那么有 T i T_i Ti继承 T i − 1   T r o o t T_i-1 ~ T_root Ti1 Troot. 当一个子节点已经具备属性 a a a时,它不可剥离 a a a属性,也就是它的儿子的继承集合永远是 [ . . . , a , . . . . ] [..., a , ....] [...,a,....],不可能再单独出现属性 b b b,而当有一个子节点同时继承了 a a a属性与 b b b属性,也就是他的继承中有子集 [ a , b ] [a,b] [a,b],那么他的祖先要么继承 a a a要么继承 b b b,然后经过一条带有特性 b b b或特性 a a a的边连接。即若同时出现了一个节点连接 a a a,一个节点连接 b b b,一个节点只连接 a 、 b a、b ab,那么必然会出现两条a或两条 b b b,不符合要求。

  • 例:
    就比如说子节点 1 1 1继承了 [ a ] [a] [a],子节点 2 2 2继承了 [ b ] [b] [b],子节点 3 3 3继承了 [ a , b ] [a,b] [a,b]
    那么子节点 3 3 3若是子节点 1 1 1的儿子,那么他们俩之间是连接了一条 b b b特性的边,即 子节点1 [ a ] + b — — > [a] + b ——> [a]+b>子节点3 [ a , b ] [a,b] [a,b]
    而节点2 [ b ] [b] [b]此时不可能由子节点1得来,更不可能从子节点3得来,
    s o so so,那么子节点 2 2 2就只能从根节点得来,他们之间需要连接一条特性b的边。即 r o o t [ ] + b — — > root[]+ b ——> root[]+b> 子节点2 [ b ] [b] [b]
    s o so so这样就有两条特性b的边,违背题目条件,无法构造一棵可以解释所有子种群产生途径的进化树了。
    同理,若子节点 3 3 3若是子节点 2 2 2的儿子,也无法构造一棵可以解释所有子种群产生途径的进化树。

代码

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<set>
using namespace std;
int n;
string s1,s2;
bool A_B , A ,B;
set<string> h[30]; 
set<string> S;
int main()
{
	freopen("evolution.in","r",stdin);
	freopen("evolution.out","w",stdout);
	scanf("%d",&n);
	string s;
	int m;
	for (int i = 1; i <= n; i++)
	{
		cin>>m;
		for (int j = 1; j <= m; j++)
		{
			cin >> s;
			h[i].insert(s);
			S.insert(s);
		}
	}
	for (set<string>::iterator i = S.begin(); i != S.end(); i++)
	{
		for (set<string>::iterator j = i; j != S.end(); j++)
		{
			A_B = false , A = false , B = false; 

			if (*i == *j)
				continue;
			s1 = *i;
			s2 = *j;
			for (int k = 1; k <= n; k++)
			{
				if (h[k].count(s1)&&h[k].count(s2))
				{
					A_B = true;
					continue;
				}
				if (h[k].count(s1))
				{
					A = true;
					continue;
				}
				if (h[k].count(s2))
					B = true;
			}
			if (A_B&&A&& B)
			{
				cout<< "no" <<endl;
				return 0;
			}
		}
	}
	cout << "yes" << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值