小韦老师@神犇营-my1060-家谱

小韦老师@神犇营-my1060-家谱

题目:

描述

家谱,又称族谱、宗谱等,是一种以表谱形式,记载一个家族的世系繁衍及重要人物事迹的书。皇帝的家谱称玉牒,如新朝玉牒、皇宋玉牒。它以记载父系家族世系、人物为中心,由正史中的帝王本纪及王侯列传、年表等演变而来。

家谱是一种特殊的文献,就其内容而言,是中国五千年文明史中具有平民特色的文献,记载的是同宗共祖血缘集团世系人物和事迹等方面情况的历史图籍。家谱属珍贵的人文资料,对于历史学、民俗学、人口学、社会学和经济学的深入研究,均有其不可替代的独特功能。

这一天小码猿拿到了自己家的家谱,小码猿便想知道,在自己家的家谱中,每位祖先有多少直系后代(直系后代包括他的孩子和他孩子的直系后代)。但是家族历史源远流长,家谱实在太庞大了,自己一个人完全数不过来。热心的你便自告奋勇帮小码猿写一个程序,来统计每位祖先有多少直系后代。

输入

输入的第一行有一个整数 n( 1 ≤ n ≤ 30000),表示家谱中的总人数。

接下来读入 n - 1 行,每行有两个整数 x, y(1 ≤ x, y ≤ n),表示 x 是 y 的父母。

输出

输出 n 行,每行有一个整数,表示第 i 个人有多少个直系后代。

输入样例1

4
1 2
1 3
2 4

输出样例1

3
1
0
0

题解:

思路

整体思路:

这个家谱是个特殊的有向图(其实是树,树就是一种特殊的图)。把这个图建好之后,枚举每个顶点,数当前这个顶点出发能遍历到的点的数量,即为题目所求。

主要步骤:

1、数据结构:

用一个 vector 数组作为邻接表存储图,例如 child[1] 这个 vector 存储的是 1 这个人的所有孩子也即可以认为是 1 这个顶点能到达的顶点:

	const int N = 3e4 + 10;
	vector child[N]; 

2、输入并存储图的信息

	for (int i = 1; i < n; i++) {
		cin >> x >> y;
		child[x].push_back(y);  // x 是 y 的父母  
	}

3、调用 DFSTrave 函数(求得每个顶点的直系后代,并输出)

	DFSTrave();

4、实现 DFSTrave 函数,求得每个顶点的直系后代,并输出:

	void DFSTrave() {
		for (int u = 1; u <= n; u++) { // 枚举每个顶点 
			cnt = 0;  // 计数器归 0(用来数有多少个直系后代) 
			DFS(u);  // 调用 DFS 函数,遍历所有 u 的直系后代 
			cout << cnt << endl;  // 输出直系后代的数量 
		}
	} 

5、实现 DFS 函数,遍历所有 u 的直系后代:

	void DFS(int u) {
		// 枚举 u 的所有孩子 
		for (int v = 0; v < child[u].size(); v++) {
			DFS(child[u][v]);  // 递归对 u 的孩子调用 DFS 
			cnt++;  // 直系后代数量加 1 
		}
	}

思考:

1°图和树有什么关系?

2°进一步地,图的线性表有什么关系?

3°这里的直系后代可以理解为一种认为定义的特殊的“连通块”吗?如果是,这里的“连通块”应该如何定义?

完整代码

#include 

using namespace std;

// 用一个 vector 数组作为邻接表存储图,例如 child[1] 这个 vector 存储的是 1 这个人的所有孩子
// 也即可以认为是 1 这个顶点能到达的顶点 
const int N = 3e4 + 10;
vector child[N];  
int n, cnt;

// 遍历所有 u 的直系后代 
void DFS(int u) {
	// 枚举 u 的所有孩子 
	for (int v = 0; v < child[u].size(); v++) {
		DFS(child[u][v]);  // 递归对 u 的孩子调用 DFS 
		cnt++;  // 直系后代数量加 1 
	}
}

// 求得每个顶点的直系后代,并输出
void DFSTrave() {
	for (int u = 1; u <= n; u++) { // 枚举每个顶点 
		cnt = 0;  // 计数器归 0(用来数有多少个直系后代) 
		DFS(u);  // 调用 DFS 函数,遍历所有 u 的直系后代 
		cout << cnt << endl;  // 输出直系后代的数量 
	}
}

int main() {
 
	cin >> n;
	int x, y;
	// 输入并存储图的信息 
	for (int i = 1; i < n; i++) {
		cin >> x >> y;
		child[x].push_back(y);  // x 是 y 的父母
	}
	// 调用 DFSTrave 函数(求得每个顶点的直系后代,并输出) 
	DFSTrave();
	
	return 0;
}

我是小韦老师,企者不立,跨者不行,每天进步一点点。

欢迎大家多多交流,如果发现有错误,请多指正。有疑问的同学也可以留言评论或者发邮件。邮箱:[email protected]

你可能感兴趣的:(小韦同学@题解:神犇营)