洛谷1983——拓扑排序

题目传送门
https://www.luogu.com.cn/problem/P1983

本题考查的是图论中的拓扑排序,题目难度普通+,题目非常典型,是一道好题,单纯考察拓扑排序的使用,AC代码如下:

//拓扑排序

#include 
#include 
#include 

const int maxn = 1010;

using namespace std;
int n, m;
int G[maxn][maxn], flag[maxn], route[maxn], outDegree[maxn], vis[maxn], nowzero[maxn];

int main() {

	scanf("%d%d", &n, &m);
	memset(G, -1, sizeof(G));
	memset(outDegree, 0, sizeof(outDegree));
	memset(vis, -1, sizeof(vis));
	//生成图

	for (int i = 0; i < m; i++) {
		int stop_num;
		memset(flag, -1, sizeof(flag));
		scanf("%d", &stop_num);
		//存储停靠的车站
		for (int j = 1; j <= stop_num; j++) {
			scanf("%d", &route[j]);
			flag[route[j]] = 1;
		}
		//遍历起点和终点之间所有未被停靠的车站,如果有,就连接每一个停靠的车站和它
		for (int j = route[1]; j <= route[stop_num]; j++) {
			if (flag[j] == -1) {//找到当前未停靠的车站
				for (int k = 1; k <= stop_num; k++) {//遍历所有route[k],连接j和route[k],G[j][route[k]]表示有从route[k]到j的一条边
					if (G[j][route[k]] == -1) {
						G[j][route[k]] = 1;
						outDegree[route[k]] += 1;
					}					
				}
			}
		}
	}

	int layernum;
	int ans = 0;
	do {
		layernum = 0;
		//删除出度为0的节点
		for (int i = 1; i <= n; i++) {
			if (outDegree[i] == 0 && vis[i] == -1) {
				nowzero[layernum++] = i;
				vis[i] = 1;
			}
		}
		//找到本轮被删除的所有节点,将对应的边都删除
		for (int i = 0; i < layernum; i++) {
			for (int j = 1; j <= n; j++) {
				if (G[nowzero[i]][j] == 1) {
					G[nowzero[i]][j] = -1;
					outDegree[j] -= 1;
				}
			}
		}
		ans++;

	} while (layernum);

	printf("%d", ans-1);
	

	return 0;
}

小细节:
因为本题的节点数量最高为1e4,所以可以使用邻矩阵建立图结构,简化代码和思考过程。

你可能感兴趣的:(计算机保研机试准备)