Official

H - Prerequisites Editorial by cn449


\(1\) から \(N\) までの番号が付いた \(N\) 頂点の有向グラフであって、\(i\) から \(P_{i,j}\) に辺を張ったものを \(G\) とおきます。すべての本を読むことが可能であるという制約から、このグラフは DAG です。
\(1\) を読むために本 \(i\) を読む必要があることの必要十分条件は \(G\) において \(1\) を始点、\(i\) を終点とするパスが存在することです。 したがって、\(1\) を始点とする BFS を行うことなどで読む必要のある本の集合を求めることができます。
本の読む順については、\(G\) のトポロジカル順の逆順に読むことで目的を達成できます。

実装例

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;

vector<int> topological_sort(vector<vector<int>> graph) {
	int n = graph.size();
	vector<int> indegree(n);
	for (int i = 0; i < n; i++) for (int j : graph[i]) indegree[j]++;
	vector<int> res;
	queue<int> que;
	for (int i = 0; i < n; i++) if (indegree[i] == 0) que.push(i);
	while (!que.empty()) {
		int ver = que.front(); que.pop();
		res.push_back(ver);
		for (int i : graph[ver]) {
			indegree[i]--;
			if (indegree[i] == 0) que.push(i);
		}
	}
	return res;
}

int main() {
	int n;
	cin >> n;
	vector<vector<int>> graph(n, vector<int>());
	rep(i, n) {
		int c;
		cin >> c;
		rep(_, c) {
			int v;
			cin >> v;
			v--;
			graph[i].push_back(v);
		}
	}
	queue<int> que;
	que.push(0);
	vector<bool> f(n);
	while (!que.empty()) {
		int q = que.front(); que.pop();
		for (int i : graph[q]) {
			if (!f[i]) {
				f[i] = true;
				que.push(i);
			}
		}
	}
	vector<int> t = topological_sort(graph);
	vector<int> order(n);
	rep(i, n) order[t[i]] = i;
	vector<int> ans;
	for (int i = 1; i < n; i++) if (f[i]) ans.push_back(i);
	sort(ans.begin(), ans.end(), [&](int x, int y) {return order[x] > order[y]; });
	for (int i = 0; i < ans.size(); i++) cout << ans[i] + 1 << " \n"[i == ans.size() - 1];
}

posted:
last update: