Experimento avanzado 4-3.1 Procesamiento de genealogía (30 puntos)

La investigación antropológica está muy interesada en las familias, por lo que los investigadores han recopilado genealogías de algunas familias para su investigación. En el experimento, se utilizó una computadora para procesar el árbol genealógico. Para lograr este objetivo, los investigadores convirtieron el árbol genealógico en un archivo de texto. El siguiente es un ejemplo de un archivo de texto de árbol genealógico:

 

En el archivo de texto del árbol genealógico, cada línea contiene el nombre de una persona. El nombre de la primera línea es el antepasado más antiguo de esta familia. El árbol genealógico contiene solo los descendientes del antepasado más antiguo y sus maridos o esposas no aparecen en el árbol genealógico. Los hijos de todos tienen sangría 2 espacios más que sus padres. Genealogía sobre archivo de texto, por ejemplo, Johnlos primeros antepasados ​​de la familia, tiene dos hijos Roberty Nancy, Robertcon dos hijos Franky Andrew, Nancysólo un hijo David.

En el experimento, los investigadores también recopilaron documentos familiares y extrajeron declaraciones sobre la relación entre dos personas en el árbol genealógico. Los siguientes son ejemplos de declaraciones en el árbol genealógico:

 

El investigador necesita juzgar si cada afirmación es verdadera o falsa. Por favor, escriba un programa para ayudar al investigador a juzgar.

Formato de entrada:

La entrada primero da 2 números enteros positivos N (2≤N≤100) y M (≤100), donde N es el número de nombres en el árbol genealógico, M es el número de declaraciones en el árbol genealógico y cada línea de entrada no excede los 70 caracteres .

La cadena del nombre consta de no más de 10 letras en inglés. No hay espacio de sangría antes del nombre dado en la primera línea de la genealogía. Otros nombres en el árbol genealógico deben tener una sangría de al menos 2 espacios, es decir, son descendientes del antepasado más antiguo en el árbol genealógico (el nombre dado en la primera línea), y si un nombre en el árbol genealógico tiene una sangría de k espacios antes del nombre, el nombre en la siguiente línea será como máximo Sangra k + 2 espacios.

El mismo nombre no aparecerá dos veces en una genealogía, y los nombres que no aparecen en la genealogía no aparecerán en la declaración. El formato de cada declaración es el siguiente, donde Xy Yhay diferentes nombres en el árbol genealógico:

 

Formato de salida:

Para cada oración de declaración en el caso de prueba, la salida en una línea True, si la declaración es verdadera o Falsesi la declaración es falsa.

Muestra de entrada:

 

Salida de muestra:

 

Para esta pregunta, mis amigos a mi alrededor usan mapas múltiples y mapeos. Todavía me gusta usar la lista binaria enlazada del hijo izquierdo y el hermano derecho de mi viejo amigo.

El tipo de esta pregunta es similar a los puntos de conocimiento del árbol de directorios que presenté en el artículo anterior, pero creo que esta pregunta como experimento avanzado es mucho más simple que el experimento básico del árbol de directorios. La idea es usar una pila para construir un árbol con recorrido de preorden, escribir una función para consultar la posición de un nodo en el árbol y luego escribir una función de Juez para determinar si la relación es correcta. La lógica del juicio también es muy simple. No hay mucho que decir, solo muestre el código directamente y escriba comentarios detallados sobre el código, debería ser fácil de entender la idea. Por supuesto, la función de juez se puede optimizar. La abuela Chen dijo que se puede optimizar en dos casos, pero soy demasiado vago para optimizar. Es más sencillo dividirlo en cinco casos. Pero la abuela Chen también propuso una forma de optimizar este código, es decir, construir un árbol de búsqueda binario para el nombre de la persona. Esta consulta es más eficiente. Colocaré este hoyo aquí por un tiempo y luego lo llenaré. Si está interesado en él, Puedes comunicarte conmigo.

Tenga en cuenta que tenemos que ingresar a un bucle para determinar la relación entre el número de nodos leídos y el número de nodos leídos en el anterior, por lo que el primer nodo necesita un tratamiento especial porque el primer nodo no lo hace. El último nodo, por lo que antes de ingresar al ciclo, primero construimos un árbol binario con un nodo y leemos el antepasado más antiguo en este nodo y dejamos que preNode apunte al nodo del antepasado más antiguo. Después de eso, ingresamos nuevamente al bucle.

#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<iostream>
#include<stack>
using namespace std;
int N,M;
struct TreeNode
{
	string name;
	int layer;
	TreeNode* child;
	TreeNode* sibling;
};
typedef TreeNode* PtrToTreeNode;
typedef PtrToTreeNode BinTree;
BinTree CreateNode(string name, int layer)
{
	PtrToTreeNode Node = new TreeNode;
	Node->name = name;
	Node->layer = layer;
	Node->child = NULL;
	Node->sibling = NULL;
	return Node;
}
BinTree CreateFamilyTree()
{
	int i,j,cnt,layer;//cnt用来记录空格的个数
	PtrToTreeNode Node,preNode,tmpNode;
	string s;
	stack<BinTree> sta;
	getline(cin,s);//不要用cin,cin会忽略掉单词前面的空格
	PtrToTreeNode root = CreateNode(s,0);//创建一颗只有根结点的二叉树并读入最早的祖先
	preNode = root;//令preNode指向根结点
	for(i=1; i<N; i++)//开始逐行读入人名并插入二叉树
	{
		cnt = 0;
		getline(cin,s);
		for(j=0; j<s.length(); j++)//计算空格的个数
		{
			string ss = s.substr(j,1);
			if(ss==" ")
				cnt++;
		}
		Node = CreateNode(s.substr(cnt,s.length()-cnt),cnt/2);
		if(Node->layer>preNode->layer)//如果层数大于前一个结点就插入它的左孩子
		{
			Node->sibling = preNode->child;
			preNode->child = Node;
			preNode = Node;
			sta.push(Node);//压入栈中
		}
		else if(Node->layer==preNode->layer)//层数相等说明是兄弟,插入其右兄弟的位置
		{
			Node->sibling = preNode->sibling;
			preNode->sibling = Node;
			preNode = Node;
			sta.push(Node);//压入栈中
		}
		else//层数大于前一个结点,说明这个结点应该是前一个结点的长辈,逐个弹出栈中的结点并检查
		{   //直到碰到某个结点的层数与之相同,然后插入到这个结点右兄弟位置
			while(true)
			{
				tmpNode = sta.top(); sta.pop();
				if(tmpNode->layer==Node->layer)
				{
					Node->sibling = tmpNode->sibling;
					tmpNode->sibling = Node;
					preNode = Node;
					sta.push(Node);//压入栈中
					break;
				}
			}
		}
	}
	return root;
}
PtrToTreeNode search(BinTree BT, string name)//递归的查找函数
{
	BinTree ans1,ans2;
	if(!BT) return NULL;//BT为NULL,说明查找失败,返回NULL
	if(BT->name == name)//找到了,return 地址
		return BT;
	else//未找到,分别从左孩子和右兄弟处继续递归的查找
	{
		ans1 = search(BT->child,name);
		ans2 = search(BT->sibling,name);
	}
	if(ans1) return ans1;//如果在左孩子的子树找到了就直接return地址
	else
		return ans2;//左孩子子树没找到,那就直接return右兄弟的查询结果即可
	
}
void Judge(BinTree root)//判断函数
{
	int i;BinTree x,y,ptr;
	string str[6];
	for(i=0; i<6; i++)
		cin>>str[i];
	if(str[3]=="child")
	{
		y = search(root,str[5]);//先找到父亲的位置
		if(y->child == NULL) { printf("False\n"); return; }//如果父亲没孩子,说明错误
		if(y->child->name == str[0]) { printf("True\n"); return; }//有孩子且名字也一样,说明正确
		ptr = y->child->sibling;//第一个孩子不是,那么从第一个孩子的兄弟开始找 
		while(ptr)//遍历他的所有兄弟
		{
			if(ptr->name == str[0]) { printf("True\n"); return; }
			ptr = ptr->sibling;
		}
		//都没找到,那就说明错误了
		printf("False\n"); return;
	}
	if(str[3]=="parent")//同上,把str[0]和str[5]换一下就可以了
	{
		y = search(root,str[0]);
		if(y->child == NULL) { printf("False\n"); return; }
		if(y->child->name == str[5]) { printf("True\n"); return; }
		ptr = y->child->sibling; 
		while(ptr)
		{
			if(ptr->name == str[5]) { printf("True\n"); return; }
			ptr = ptr->sibling;
		}
		printf("False\n"); return;
	}
	if(str[3]=="ancestor")
	{
		x = search(root,str[0]);//先定位祖先的位置
		y = search(x->child,str[5]);//在其孩子为根的子树中查找str[5],注意不要在以x为根的子树中去寻找,因为x的右兄弟不是x的子孙后代
		if(y)//找到了
		{
			printf("True\n"); return;
		}
		else//没找到
		{
			printf("False\n"); return;
		}
	}
	if(str[3]=="descendant")//思路同上
	{
		x = search(root,str[5]);
		y = search(x->child,str[0]);
		if(y)
		{
			printf("True\n"); return;
		}
		else
		{
			printf("False\n"); return;
		}
	}
	if(str[3]=="sibling")//判断兄弟关系
	{
		x = search(root,str[0]);//先定位兄弟str[0]
		ptr = x->sibling;
		while(ptr)//一直往右去找他的兄弟str[5],如果找到了就return true,没找到也不要紧
		{
			if(ptr->name == str[5])
			{
				printf("True\n"); return;
			}
			ptr=ptr->sibling;
		}
		x = search(root,str[5]);//定位兄弟str[5]
		ptr = x->sibling;
		while(ptr)//一直往右去找他的兄弟str[5],如果找到了就return true,没找到那就直接可以return false了
		{
			if(ptr->name == str[0])
			{
				printf("True\n"); return;
			}
			ptr=ptr->sibling;
		}
		printf("False\n"); return;
	}
}
int main()
{
	int i,j;
	string s;
	scanf("%d%d\n",&N,&M);
	BinTree root = CreateFamilyTree();//建树
	for(i=0; i<M; i++)//判断并输出
	{
		Judge(root);
	}
	return 0;
}

 

Supongo que te gusta

Origin blog.csdn.net/yiwaite/article/details/100902887
Recomendado
Clasificación