数据结构练习 01-图的遍历

题目描述

给出N个点,M条边的有向图,对于每个点v,求A(v)表示从点v出发,能到达的编号最大的点。

输入格式

第1行,2个整数N,M

接下来M行,每行2个整数Ui,Vi,表示边(Ui,Vi)。点用1,2,⋯,N编号。

输出格式

N个整数A(1),A(2),⋯,A(N)

输入输出样例

输入

4 3
1 2
2 4
4 3

输出

4 4 3 4

解题思路及代码

首先明确这是一个有向图。

struct Graph {
	int vexnum;
	vector<vector<int>> adj;
};

该题需要对一个有向图进行遍历,用ans数组来记录每个节点遍历的最大值。其特点是若在一条遍历路径中找到一个最大值,则该最大值之前的所有节点的ans 都应该是这个最大值。换句话说,遍历是沿着路径向前的,但是结果是要向后写的。

最初的解法是从小到大逐个遍历,每次遍历有一个最大值m,若碰到已经有结果的节点,则比较该节点的ansm的大小,完成所有节点的遍历后得到该节点的ans

int main() {
	Graph g;
	int m;
	cin >> g.vexnum >> m;
	g.adj.resize(g.vexnum);
	vector<int> ans(g.vexnum, -1);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		g.adj[a - 1].push_back(b - 1);
	}
	for (int i = 0; i < g.vexnum; i++) {
		if (ans[i] > 0) continue;
		vector<int> T(g.vexnum, 0);
		queue<int> q;
		int temp = i;
		q.push(i);
		T[i] = 1;
		while (!q.empty()) {
			int f = q.front();
			q.pop();
			for (int j = 0; j < g.adj[f].size(); j++) {
				if (!T[g.adj[f][j]]) {
					if (ans[g.adj[f][j]] >= 0) {
						if (temp < ans[g.adj[f][j]]) {
							temp = ans[g.adj[f][j]];
						}
					}
					else {
						if (g.adj[f][j] > temp) {
							temp = g.adj[f][j];
						}
						q.push(g.adj[f][j]);
					}
					T[g.adj[f][j]] = 1;
				}
			}
		}
		ans[i] = temp;
	}
	for (int i = 0; i < g.vexnum - 1; i++) {
		cout << ans[i] + 1 << " ";
	}
	cout << ans[g.vexnum - 1] + 1;
	return 0;
}

该解法有一个明显的缺点是节点重复遍历,当数据量较大时无法在规定时间内完成。因此目标应该是争取能做到一次遍历就能得到结果,尽量少的遍历次数应该是做这类题目的共同特征。

因此可以采取反向建边的思路,即将有向图的方向全部倒置。从值最大的节点开始遍历,每次遍历经过的节点的ans即为该次遍历的开始节点的值。

int main() {
	Graph g;
	int m;
	cin >> g.vexnum >> m;
	g.adj.resize(g.vexnum);
	vector<int> ans(g.vexnum, -1);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		g.adj[b - 1].push_back(a - 1);
	}
	for (int i = g.vexnum - 1; i >= 0; i--) {
		if (ans[i] >= 0) continue;
		ans[i] = i;
		queue<int> q;
		q.push(i);
		while (!q.empty()) {
			int f = q.front();
			q.pop();
			for (int j = 0; j < g.adj[f].size(); j++) {
				if (ans[g.adj[f][j]] < 0) {
					ans[g.adj[f][j]] = i;
					q.push(g.adj[f][j]);
				}
			}
		}
	}
	for (int i = 0; i < g.vexnum - 1; i++) {
		cout << ans[i] + 1 << " ";
	}
	cout << ans[g.vexnum - 1] + 1;
	return 0;
}

参考资料

1.洛谷_P3916 图的遍历:https://www.luogu.com.cn/problem/P3916
2.洛谷题解_hongzy 的博客:https://www.luogu.com.cn/blog/hongzy/solution-p3916

posted @ 2020-12-28 00:23  埃利安里  阅读(413)  评论(0)    收藏  举报