题目描述:某个大型软件项目的构建系统拥有 N 个文件,文件编号从 0 到 N - 1,在这些文件中,某些文件依赖于其他文件的内容,这意味着如果文件 A 依赖于文件 B,则必须在处理文件 A 之前处理文件 B (0 <= A, B <= N - 1)。请编写一个算法,用于确定文件处理的顺序。
输入描述:第一行输入两个正整数 N, M。表示 N 个文件之间拥有 M 条依赖关系。后续 M 行,每行两个正整数 S 和 T,表示 T 文件依赖于 S 文件。
输出描述:输出共一行,如果能处理成功,则输出文件顺序,用空格隔开。 如果不能成功处理(相互依赖),则输出 -1。
拓扑排序主要用来解决:
1.给出一个 有向图,把这个有向图转成线性的排序 就叫拓扑排序。
2.拓扑排序也要检测这个有向图 是否有环,即存在循环依赖的情况,所以拓扑排序也是图论中判断有向无环图的常用方法。
我们做拓扑排序的时候,应该优先找 入度为 0 的节点,只有入度为0,它才是出发节点。 理解以上内容很重要!拓扑排序的过程,其实就两步:1.找到入度为0 的节点,加入结果集;2.将该节点从图中移除。循环以上两步,直到 所有节点都在图中被移除了。
代码如下:
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
int main() {
int m, n, s, t;
cin >> n >> m;
vector<int> inDegree(n, 0); // 记录每个文件的入度
unordered_map<int, vector<int>> umap;// 记录文件依赖关系
vector<int> result; // 记录结果
while (m--) {
// s->t,先有s才能有t
cin >> s >> t;
inDegree[t]++; // t的入度加一
umap[s].push_back(t); // 记录s指向哪些文件
}
queue<int> que;
for (int i = 0; i < n; i++) {
// 入度为0的文件,可以作为开头,先加入队列
if (inDegree[i] == 0) que.push(i);
}
while (que.size()) {
int cur = que.front(); // 当前选中的文件
que.pop();
result.push_back(cur);
vector<int> files = umap[cur]; //获取该文件指向的文件
if (files.size()) { // cur有后续文件
for (int i = 0; i < files.size(); i++) {
inDegree[files[i]] --; // cur的指向的文件入度-1
if(inDegree[files[i]] == 0) que.push(files[i]);
}
}
}
if (result.size() == n) {
for (int i = 0; i < n - 1; i++) cout << result[i] << " ";
cout << result[n - 1];
} else cout << -1 << endl;
return 0;
}