ZOJ Problem Set - 2348

5 篇文章 0 订阅
2 篇文章 0 订阅

原题:

Hire and Fire

Time Limit: 2 Seconds       Memory Limit: 65536 KB

In this problem, you are asked to keep track of the hierarchical structure of an organization's changing staff. As the first event in the life of an organization, the Chief Executive Officer (CEO) is named. Subsequently, any number of hires and fires can occur. Any member of the organization (including the CEO) can hire any number of direct subordinates, and any member of the organization (including the CEO) can be fired. The organization's hierarchical structure can be represented by a tree. Consider the example shown by Figure 1:

VonNeumann is the CEO of this organization. VonNeumann has two direct subordinates: Tanenbaum and Dijkstra. Members of the organization who are direct subordinates of the same member are ranked by their respective seniority. In the diagram, the seniority of such members decrease from left to right. For example Tanenbaum has higher seniority than Dijkstra.

When a member hires a new direct subordinate, the newly hired subordinate has lower seniority than any other direct subordinates of the same member. For example, if VonNeumann (in Figure 1) hires Shannon, then VonNeumann's direct subordinates are Tanenbaum, Dijkstra, and Shannon in order of decreasing seniority.

When a member of the organization gets fired, there are two possible scenarios. If the victim (the person who gets fired) had no subordinates, then he/she will be simply dropped from the organization's hierarchy. If the victim had any subordinates, then his/her highest ranking (by seniority) direct subordinate will be promoted to fill the resulting vacancy. The promoted person will also inherit the victim's seniority. Now, if the promoted person also had some subordinates then his/her highest ranking direct subordinate will similarly be promoted, and the promotions will cascade down the hierarchy until a person having no subordinates has been promoted. In Figure 1, if Tanenbaum gets fired, then Stallings will be promoted to Tanenbaum's position and seniority, and Knuth will be promoted to Stallings' previous position and seniority.

Figure 2 shows the hierarchy resulting from Figure 1 after (1) VonNeumann hires Shannon and (2) Tanenbaum gets fired:

This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.

Input

The first line of each input block contains only the name of the person who is initially the CEO. All names in the input consist of 2 to 20 characters, which may be upper or lower case letters, apostrophes, and hyphens. (In particular, no blank spaces.) Each name contains at least one upper case and at least one lower case letter.

The first line will be followed by one or more additional lines. The format of each of these lines will be determined by one of the following three rules of syntax:

  • [existing member] hires [new member]
  • fire [existing member]
  • print

Here [existing member] is the name of any individual who is already a member of the organization, [new member] is the name of an individual who is not a member of the organization as yet. The three types of lines (hires, fire, and print) can appear in any order, any number of times.

You may assume that at any time there is at least one member (who is the CEO) and no more than 1000 members in the organization.

Output

For each print command, print the current hierarchy of the organization, assuming all hires and fires since the beginning of the input have been processed as explained above. Tree diagrams (such as those in Figures 1 and 2) are translated into textual format according to the following rules:

  • Each line in the textual representation of the tree will contain exactly one name.
  • The first line will contain the CEO's name, starting in column 1.
  • The entire tree, or any sub-tree, having the form



    will be represented in textual form as:

The output resulting from each print command in the input will be terminated by one line consisting of exactly 60 hyphens. There will not be any blank lines in the output.

Sample Input

1

VonNeumann
VonNeumann hires Tanenbaum
VonNeumann hires Dijkstra
Tanenbaum hires Stallings
Tanenbaum hires Silberschatz
Stallings hires Knuth
Stallings hires Hamming
Stallings hires Huffman
print
VonNeumann hires Shannon
fire Tanenbaum
print
fire Silberschatz
fire VonNeumann
print

Sample Output

VonNeumann
+Tanenbaum
++Stallings
+++Knuth
+++Hamming
+++Huffman
++Silberschatz
+Dijkstra
------------------------------------------------------------
VonNeumann
+Stallings
++Knuth
+++Hamming
+++Huffman
++Silberschatz
+Dijkstra
+Shannon
------------------------------------------------------------
Stallings
+Knuth
++Hamming
+++Huffman
+Dijkstra
+Shannon
------------------------------------------------------------


源码实现:

#include <iostream>   
#include <string.h>   
#include <string>   
//#include <sstream>
using namespace std;  
#define HASH_METHOD djbhash //default hash method   
//#define _CRTDBG_MAP_ALLOC

//overall variable   
const int NAME_NUM = 21;//20 + 1   
const int HASH_LENGTH = 64;  
const char * HIRES = "hires";  
const char * FIRE = "fire";  
const char * PRINT = "print";  
enum OperationState  
{  
	start,hires,fire,print  
};  

//hash method   
int djbhash(char *str)  
{  
	unsigned int hash = 5381;  
	while (*str)  
	{  
		hash += (hash << 5) + (*str++);  
	}  
	return (hash & 0x7FFFFFFF) % HASH_LENGTH;  
}  
int times33(char *str)  
{  
	unsigned int hash = 0;  
	while(*str)  
	{  
		hash += hash * 33 + (*str++);  
	}  
	return hash % HASH_LENGTH;  
}  

//tree   
struct MemNode  
{  
	char * name;  
	MemNode * father;  
	MemNode * son;  
	MemNode * brother;  
	MemNode * next;//hash ptr, point to the next hash node   
	MemNode * pre;//hash ptr, point to the pre hash node   
};  
//hash array   
MemNode * hash_array[HASH_LENGTH];  
//hash method   
void insert_hash_array(MemNode * node)  
{  
	if(node == 0)  
		return;  
	int hash_value = HASH_METHOD(node->name);//use the name of MemNode to hash   
	MemNode * pos = hash_array[hash_value];  
	while(pos->next)  
	{  
		pos = pos->next;  
	}  
	pos->next = node;  
	node->pre = pos;  
}  
//tree method   
void destroy_tree(MemNode * subroot)  
{  
	if(subroot == 0)  
		return;  
	destroy_tree(subroot->son);  
	destroy_tree(subroot->brother);  

	delete subroot->name;  
	delete subroot;  
}  
//print the whole tree   
void print_tree(MemNode * subroot,int level)  
{  
	if(subroot == 0)  
		return;  
	for(int i = 0;i < level;i++)  
	{  
		cout << "+";  
	}  
	cout << subroot->name << endl;  

	print_tree(subroot->son,level+1);//print child   
	print_tree(subroot->brother,level);//then print brother   
}  

void insert_tree(MemNode * root,char * father_name,char * node_name)  
{  
	if(root == 0)  
		return;  
	char * son_name = new char[NAME_NUM];  
	strncpy(son_name,node_name,NAME_NUM);  
	MemNode * son_node = new MemNode();  
	son_node->name = son_name;  
	son_node->brother = 0;  
	son_node->son = 0;  
	son_node->pre = 0;  
	son_node->next = 0;  
	//find the father node through hash   
	MemNode * pos = hash_array[HASH_METHOD(father_name)];  
	while(pos->next)  
	{  
		if(strncmp(pos->next->name,father_name,NAME_NUM) == 0)  
		{  
			pos = pos->next;  
			break;  
		}else{  
			pos = pos->next;  
		}  
	}  
	//now pos points to the father node   
	son_node->father = pos;  

	if(pos->son == 0)  
	{  
		pos->son = son_node;  
		insert_hash_array(son_node);  
		return;  
	} 
	MemNode * son_pos = pos->son;  
	while(son_pos->brother != 0)  
	{  
		son_pos = son_pos->brother;  
	}  
	son_pos->brother = son_node;  
	insert_hash_array(son_node);  
	return;  
}  
//locate the hash node according to the name   
MemNode * find_hash_node(char * node_name)  
{  
	if(node_name == 0)  
	{  
		return 0;  
	}  
	int hash_value = HASH_METHOD(node_name);  
	MemNode * pos = hash_array[hash_value];  
	while(pos->next)  
	{  
		if(strncmp(pos->next->name,node_name,NAME_NUM) == 0)  
		{  
			return pos->next;  
		}else{  
			pos = pos->next;  
		}  
	}  
	return 0;//error: not found   
}  

//just delete the hash relationship of node name, do not delete the node object, instead, just return the pointer of it   
void delete_hash_node(MemNode * node)  
{  
	if(node == 0)  
		return;  
	node->pre->next = node->next;  

	if(node->next != 0)  
	{  
		node->next->pre = node->pre;  
	}  
	return;  
}  

void exchange_hash_node(MemNode * a,MemNode * b)  
{  
	if(a == 0 || b == 0)  
		return;  
	//exchange names   
	char * temp = a->name;  
	a->name = b->name;  
	b->name = temp;  
	//update the pre node and next node of both nodes   
	a->pre->next = b;  
	b->pre->next = a;  

	if(a->next != 0)  
	{  
		a->next->pre = b;  
	}  
	if(b->next != 0)  
	{  
		b->next->pre = a;  
	}  
	//update the pre pointer domain and next pointer domain of both nodes   
	MemNode * tmp = a->pre;  
	a->pre = b->pre;  
	b->pre = tmp;  
	tmp = a->next;  
	a->next = b->next;  
	b->next = tmp;  

}  
void delete_tree_node(char * node_name)  
{  
	if(node_name == 0)  
		return;  
	MemNode * node = find_hash_node(node_name);  
	//MemNode * tmp = node;   
	while(node->son != 0)  
	{  
		exchange_hash_node(node,node->son);//keep exchanging till encounter a node with no son, and the name to delete appears in a leaf node   
		node = node->son;  
	}  
	//the node to delete has no son, just simply delete it and re-fix its father's son pointer and brother's brother pointer if needed   
	if(node->father->son == node)//if the node to delete is the leftest son, that means father->son pointing to it   
	{  
		node->father->son = node->brother;//update father's son pointer   
	}else{  
		//find its left brother, and update left brother's brother pointer domain   
		MemNode * temp_node = node->father->son;  
		while(temp_node->brother != node)  
		{  
			temp_node = temp_node->brother;  
		}  
		//temp_node is the left brother of node   
		temp_node->brother = node->brother;//update brother's brother pointer   
	}  
	delete_hash_node(node);  
	delete node->name;
	delete node;//free node memory   
	return;  
}  
void process()  
{  
	OperationState op_state(start);  
	//initialize the hash array, that is, the first nodes of every hash list   
	for(int i = 0;i < HASH_LENGTH;i++)  
	{  
		MemNode * tmp = new MemNode();  
		tmp->brother = 0;  
		tmp->father = 0;  
		tmp->name = 0;  
		tmp->next = 0;  
		tmp->pre = 0;  
		tmp->son = 0;  
		hash_array[i] = tmp;  
	}  
	MemNode * root = new MemNode();  
	char buf[NAME_NUM];  
	char subject[NAME_NUM];  
	char ch;  

	//process the input   
	//get CEO   
	cin >> buf;  
	//getchar();//eat the Enter key   
	//cin.get();  
	char * ceo = new char[NAME_NUM];  

	strncpy(ceo,buf,NAME_NUM);  

	root->name = ceo;  
	root->son = 0;  
	root->brother = 0;  
	root->father = 0;  
	root->next = 0;  
	root->pre = 0;  
	insert_hash_array(root);  
	while(1)  
	{  
		cin.get(ch);//get the first char in stream to determine if it is need to exit the while   
		if(ch == ' ')  
		{  
			break;  
		}else{  
			cin.putback(ch);//put the first char back to the stream   
			cin >> buf;  
			//getchar(); 
			cin.get();  //eat Enter key  
		}  
		if(strncmp(buf,HIRES,NAME_NUM) == 0)  
		{  
			op_state = hires;  
		}else if(strncmp(buf,FIRE,NAME_NUM) == 0)  
		{  
			op_state = fire;  

		}else if(strncmp(buf,PRINT,NAME_NUM) == 0)  
		{  
			op_state = print;  
			//print the tree   
			//cout << "print the tree!" << endl;   
			print_tree(root,0);  
			cout << "------------------------------------------------------------" << endl;  
			op_state = start;  
		}else  
		{  
			switch(op_state)  
			{  
			case start:  
				strncpy(subject,buf,NAME_NUM);  
				break;  
			case hires:  
				{  
					//subject hires buf, and set state to start   
					//cout << subject << " hiring " << buf << endl;   
					insert_tree(root,subject,buf);  
					op_state = start;  

				}  
				break;  
			case fire:  
				{  
					//fire buf   
					//cout << buf << " fired" << endl;   
					delete_tree_node(buf);  
					op_state = start;  
				}  
				break;  
			default:  
				cerr << "Input Error!" << endl;  
			}  
		}  
	}  
	cout << endl;  
	//cout << "finish!" << endl;   
	//TODO: retrieve the memory of nodes   
	for(int i = 0;i < HASH_LENGTH;i++)  
	{  
		delete hash_array[i];  
	}  
	destroy_tree(root);  
	//_CrtDumpMemoryLeaks();

}  
int main()  
{  
	//stringstream ss;//for redirecting the cout and saving the result   
	//streambuf * coutbuf = cout.rdbuf();  
	//streambuf * re_coutbuf = ss.rdbuf();  
	//cout.rdbuf(re_coutbuf);  
	int cases;  
	cin >> cases;  
	for(int i = 0;i < cases;i++)  
	{  
		process();  
	}  
	//_CrtDumpMemoryLeaks();
	//cout.rdbuf(coutbuf);  
	//cout << ss.str();  
}  


 


主要思想:

使用多叉树存储人员关系结构,同时借鉴linux内核,在每个树节点加入一个next指针和pre指针,用于在对名字进行散列(开散列)时,指向同个槽的下一个节点。散列方法使用time33算法,参考http://www.cnblogs.com/napoleon_liu/articles/1911571.html。

(http://blog.csdn.net/cppbegginer/article/details/7800807中转载的《C++中cout重定向》)

另外,还没想出如何获取、判断用户输入的空行(即用户两次输入回车),从而跳出执行循环。如果缓冲区用string,则可参考http://bbs.csdn.net/topics/110047351。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值