浙大 PAT Advanced level 1004. Counting Leaves

A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child.
Input

Each input file contains one test case. Each case starts with a line containing 0 < N < 100, the number of nodes in a tree, and M (< N), the number of non-leaf nodes. Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]
where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID's of its children. For the sake of simplicity, let us fix the root ID to be 01.
Output

For each test case, you are supposed to count those family members who have no child for every seniority level starting from the root. The numbers must be printed in a line, separated by a space, and there must be no extra space at the end of each line.

The sample case represents a tree with only 2 nodes, where 01 is the root and 02 is its only child. Hence on the root 01 level, there is 0 leaf node; and on the next level, there is 1 leaf node. Then we should output "0 1" in a line.

Sample Input
2 1
01 1 02
Sample Output

0 1


题目中说family的总人数N<100,且ID都是两位数编号,但没有说是按照01、02、03…来编号。

题目主要需要实现树的表示及层序遍历。重新写的算法更简洁易懂一些。


第一次的解法:

#include <iostream>
#include <queue>
using namespace std;

typedef struct myElement 
{
	int			ID;
	int			level;				// 在树的哪一层
	int			flag;				// 没有孩子则为0, 有孩子为1
	int			firstchild;			// 指向第一个孩子 如果没有孩子flag设为0
	int			next;				// 指向下一个自己的相同双亲的兄弟, 如果为0则表示它为自己双亲的最后一个孩子
}Element;

Element tree[101];					// 用来存储数据 ( 不使用tree[0] )
									// 成员全部初始化为0


int locateID(const int &ID)
{	
	int index;
	for (index = 1; 0 != tree[index].ID; ++index)
	{
		if (ID == tree[index].ID)
		{
			return index;
		}
	}
	return -1;
}

int main()
{
	int M, N, K, ID;
	int freepos = 1;					// 指向第一个可用于存储数据的位置
	int parentpos;						// 父节点位置
	int curpos;							// 当前元素的位置
	int prepos;							// 前一个元素的位置
	int rootpos;						// 根的位置
	queue<int> tque;					// 用于层序遍历

	int level = 1;
	int cnt = 0;

	// 读入信息,建立树
	cin >> N >> M;
	while(M--)
	{
		cin >> ID >> K;
		parentpos = locateID(ID);
		if (-1 == parentpos)
		{
			parentpos = freepos++;
		}
		// 父节点
		tree[parentpos].ID = ID;		// 如果之前存在该ID节点, 相当于重新设置一遍
		tree[parentpos].flag = 1;

		// 输入的M行为“非叶子”节点,即它至少有一个孩子
		--K;
		cin >> ID;
		curpos = locateID(ID);
		if (-1 == curpos)
		{
			curpos = freepos++;
		}
		tree[parentpos].firstchild = curpos;			// 补充设置父节点的第一个孩子

		// 设置第一个孩子节点
		// 孩子节点flag不需要改动, 如果它没有孩子, 保持0即可
		// 孩子节点next位不用动, 保持初始状态的0即可
		tree[curpos].ID = ID;			// 如之前存在此ID, 重新设置不会引起错误

		prepos = curpos;
		while (K--)
		{
			cin >> ID;
			curpos = locateID(ID);
			if (-1 == curpos)
			{
				curpos = freepos++;
			}
			tree[prepos].next = curpos;		// 补充设置前一个孩子节点的信息
			// 设置当前孩子节点
			tree[curpos].ID = ID;			// 如果之前存在该ID, 重复设置不会引起错误
			prepos = curpos;
		}
	}

	rootpos = locateID(1);
	tree[rootpos].level = 1;
	tque.push(rootpos);

	// 层序遍历, 确定每个节点在哪一层
	while (!tque.empty())
	{
		parentpos = tque.front();
		tque.pop();

		if (level != tree[parentpos].level)
		{
			++level;							// 新的一层, 重新开始计数
			cout << cnt << ' ';
			cnt = 0;
		}

		if (0 == tree[parentpos].firstchild)
		{
			++cnt;
		}



		curpos = tree[parentpos].firstchild;
		while (0 != curpos)
		{
			tree[curpos].level = tree[parentpos].level+1;
			tque.push(curpos);
			curpos = tree[curpos].next;						// 处理下一个节点
		}
	}

	cout << cnt << endl;

	// system("pause");
	return 0;
}

第二次解法:


#include <iostream>
#include <vector>
#include <queue>
using namespace std;

class person
{
public:
	person(): level(0), kids(){}
	int level;
	vector<int> kids;
};

person family[105];
int M, N, K;
vector<int> res;

void levelOrderTranverse(int root)
{
	queue<int> nq;
	int index, ncount = 0, level = 0;

	nq.push(root);
	while (!nq.empty())
	{
		index = nq.front();
		nq.pop();
		/* 说明已经开始处理下一层的数据 */
		if (family[index].level != level)
		{
			res.push_back(ncount);
			ncount = 0;
			++level;
		}
		if (family[index].kids.empty())
		{
			++ncount;
		}
		else
		{
			for (int i = 0; i != family[index].kids.size(); ++i)
			{
				family[family[index].kids[i]].level = family[index].level+1;
				nq.push(family[index].kids[i]);
			}
		}
	}
	res.push_back(ncount);
}


int main()
{
	int id, root = 1;
	cin >> N >> M;
	for (int i = 0; i != M; ++i)
	{
		cin >> id >> K;
		family[id].kids.resize(K);
		for (int j = 0; j != K; ++j)
		{
			cin >> family[id].kids[j];
		}
	}

	levelOrderTranverse(root);

	for (int i = 0; i != res.size(); ++i)
	{
		if (0 != i)
		{
			cout << ' ';
		}
		cout << res[i];
	}
	cout << endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值