博弈搜索练习--POJ-2003 Hire and Fire

公司里的那点事儿

描述

对于一间公司来说,它成立之时所做的第一件事恐怕就是任命CEO了。之后,CEO就会开始雇用员工,也会有员工离职去别的公司。假设公司中的每一个员工(包括 CEO在内)都可以直接雇用新的员工,而公司中的所有员工(包括CEO)也都可能会跳槽离开,则某公司在成立一段时间之后的的组织结构如图1:


VonNeumann是公司的CEO,他直接雇用了两个人,分别是Tanenbaum和Dijkstra。在公司中,某员工的几个直接下属,他们的职位是由员工们的工龄决定的,在图中即表现为从从左至右职位越来越低,譬如Tanenbaum的职位就比Dijkstra要高。

当一个员工雇用了新的下属时,该下属在该员工雇佣的所有下属中,职位是最低的。假设VonNeumann又雇用了Shannon,则VonNeumann的三名下属职位从高到低分别是Tanenbaum、Dijkstra和Shannon。

当公司中的员工离职,则有两种情况。若他没有雇用任何下属,则他会被从公司的组织结构中拿掉。若他有直接的下属,则他的直接下属中职位较高的人,会升职并补上缺位。而该下属若也有下属,则他的下属中职位最高的,会补上他升值后空出的位子。以此类推,直到某个尚未雇用下属的员工升职。

假设图1中的Tanenbaum跳槽离开了,则Stallings会补上它的位置,而Knuth会补上Stallings的位置。图2图3分别展示了基于图1的两种的操作的结果。图2: VonNeumann雇用了Shannon。图3: Tanenbaum跳槽。



输入

输入的第一行是 CEO 的姓名。题目中所有的人名的长度都在2-20之间,且由大小写字母、数字和短线(减号)组成。每个名字都包含至少一个大写和一个小写字母。

在第一行后会有很多行内容,他们由如下的规则构成:

  • [老员工] hires [新员工]
  • fire [老员工]
  • print

[老员工] 是已经在公司工作的人的名字,而[新员工]是即将被雇用的员工的名字。以上三种规则组成的内容可能会按照任何顺序出现。但公司中会至少有一名员工(CEO),且公司的规模最大不会超过 1000 人。

输出

对于每一个打印命令,按照如下规则输出当前公司的结构信息:

  • 每一行包含一个人名
  • 第一行是CEO的名字,从第一列开始
  • 对于图4形式的树

  • 输出如下
  • VonNeumann
    +Tanenbaum
    ++Stallings
    +++Knuth
    +++Hamming
    +++Huffman
    ++Silberschatz
    +Dijkstra
  • *关于print的说明:从ceo开始打印,职位每降低一个等级(参考图片和输出),在名字前面加上一个加号。先序(自己->左枝->右枝)输出整棵树的节点。整棵树遍历完之后输出一行"---------"(具体长度看测试用例1)。
  • 输入以EOF结束
 测试输入关于“测试输入”的帮助期待的输出关于“期待的输出”的帮助时间限制关于“时间限制”的帮助内存限制关于“内存限制”的帮助额外进程关于“{$a} 个额外进程”的帮助
测试用例 1以文本方式显示
  1. VonNeumann↵
  2. VonNeumann hires Tanenbaum↵
  3. VonNeumann hires Dijkstra↵
  4. Tanenbaum hires Stallings↵
  5. Tanenbaum hires Silberschatz↵
  6. Stallings hires Knuth↵
  7. Stallings hires Hamming↵
  8. Stallings hires Huffman↵
  9. print↵
  10. VonNeumann hires Shannon↵
  11. fire Tanenbaum↵
  12. print↵
  13. fire Silberschatz↵
  14. fire VonNeumann↵
  15. print↵
以文本方式显示
  1. VonNeumann↵
  2. +Tanenbaum↵
  3. ++Stallings↵
  4. +++Knuth↵
  5. +++Hamming↵
  6. +++Huffman↵
  7. ++Silberschatz↵
  8. +Dijkstra↵
  9. ------------------------------------------------------------↵
  10. VonNeumann↵
  11. +Stallings↵
  12. ++Knuth↵
  13. +++Hamming↵
  14. +++Huffman↵
  15. ++Silberschatz↵
  16. +Dijkstra↵
  17. +Shannon↵
  18. ------------------------------------------------------------↵
  19. Stallings↵
  20. +Knuth↵
  21. ++Hamming↵
  22. +++Huffman↵
  23. +Dijkstra↵
  24. +Shannon↵
  25. ------------------------------------------------------------↵
1秒64M0


题意:略过。

题解:刚看到这题实在不懂这跟博弈搜索练习有什么关系,看了POJ2003的题解感觉这纯粹是在考对数据结构的掌握,尤其是对C++的STL里的一些容器的使用。(后来学长讲蒙特卡洛和UCT时说这个是练习我们建招法树用的,这道题中使用的方法可以将多叉树转为二叉树,想想确实很有道理,也很佩服当初是哪位学长找的这题用来训练招法树建立的。)

参考博客:POJ 2003 Hire and Fire (多重链表 树结构 好题)

map,list用的很强,map提供了一种对应关系容器,list提供了链表结构,这比自己写要舒坦多了。

#include<string>
#include<list>
#include<map>
#include<iostream>
using namespace std;

struct Tree
{
	Tree*father;//与父节点相连
	string name;//本节点的员工名字
	list<Tree*>sons;//本节点员工的下属
};

map<string, Tree*>StrMap;//建立员工名字与其树节点的对应关系,方便后来的查找操作
Tree *CompanyLink;

void Print(Tree*cur_node, int range)//打印输出
{
	if (!cur_node)//说明没有下属了
		return;
	for (int i = 0; i<range; i++)
		printf("+");
	cout << cur_node->name << endl;
	list<Tree*>::iterator iter = cur_node->sons.begin();//迭代器iterator
	for (; iter != cur_node->sons.end(); ++iter)//在这里++iter比iter++效率高,详见C++ iterator 前++ 后++ 效率区别
		Print(*iter, range + 1);
}
int main()
{
	CompanyLink = new Tree();//开辟内存空间
	string EmployName, StaffName, op;//上司,下属,处理hires的
	cin >> EmployName; StrMap[EmployName] = CompanyLink;
	CompanyLink->name = EmployName;
	while (cin >> EmployName)
	{
		if (EmployName != "print")
		{
			if (EmployName != "fire")//hires部分应该还是比较好理解的,用指针操作可以直接改值,不然不能改值
			{
				cin >> op >> StaffName;
				Tree*cur_node = StrMap[EmployName];
				Tree*new_node = new Tree();
				new_node->name = StaffName;
				new_node->father = cur_node;
				cur_node->sons.push_back(new_node);
				StrMap[StaffName] = new_node;
			}
			else
			{
				cin >> StaffName;
				Tree*cur_node = StrMap[StaffName];
				StrMap.erase(StaffName);
				while (cur_node->sons.size() != 0)//一个员工晋级了,则他的第一个下属会顶替他的位置,不断重复至没有下属
				{
					cur_node->name = cur_node->sons.front()->name;//当前员工的名字被其第一个下属的名字覆盖,使用覆盖操作的好处在于不会改变原有职位的职工从属关系
					StrMap.erase(cur_node->name);//删去原有的对应关系
					StrMap[cur_node->name] = cur_node;//更新新的对应关系
					cur_node = cur_node->sons.front();//当前指针移动到其第一个下属位置
				}
				cur_node->father->sons.remove(cur_node);//没有下属了,则要删除list中的当前节点,因为和前一个重复了
				delete cur_node;//释放内存空间,之前只是切断了list中的链关系,并没有释放掉内存空间 
				cur_node = NULL;//指到0,防止出错
			}
		}
		else
		{
			Print(CompanyLink, 0);
			printf("------------------------------------------------------------\n");
		}
	}
	return 0;
}







 





















































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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值