This is a problem given in the Graduate Entrance Exam in 2018: Which of the following is NOT a topological order obtained from the given directed graph? Now you are supposed to write a program to test each of the options.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N (≤ 1,000), the number of vertices in the graph, and M (≤ 10,000), the number of directed edges. Then M lines follow, each gives the start and the end vertices of an edge. The vertices are numbered from 1 to N. After the graph, there is another positive integer K (≤ 100). Then K lines of query follow, each gives a permutation of all the vertices. All the numbers in a line are separated by a space.
Output Specification:
Print in a line all the indices of queries which correspond to “NOT a topological order”. The indices start from zero. All the numbers are separated by a space, and there must no extra space at the beginning or the end of the line. It is graranteed that there is at least one answer.
Sample Input:
6 8
1 2
1 3
5 2
5 4
2 3
2 6
3 4
6 4
6
5 2 3 6 4 1
1 5 2 3 6 4
5 1 2 6 3 4
5 1 2 3 6 4
5 2 1 6 3 4
1 2 3 4 5 6
Sample Output:
0 4 5
鸣谢用户柳汀洲补充数据!
先说一下说明是拓扑序列,举个例子,比如修高数之前需要先修小学数学,修线代之前需要先修高数,那么,给出的序列就应该是 小学数学 -> 高数 -> 线代 现在如果按照这个顺序给出,就是拓扑序列,如果是 小学数学 -> 线代 -> 高数 就不能是拓扑序列了。
所以本题,只需要用数组存储某个点的入度是多少,然后如果输入的顺序不是入度都是零,说明是不行的如图:
此时初始状态,入度值就是 蓝色框框里的值 以 1 5 2 3 6 4 顺序为例把:
首先是 1 访问过 1 以后,我们需要把 1 到达的所有的点的入度都减去 1,把路径去掉 结果如图:
然后是 访问 5,同理如图
如果访问某一个节点,发现该节点的入度不是 0,说明这就不是一个拓补序列。
详解见代码:
#include<iostream>
#include<string>
#include<algorithm>
#include<bits/stdc++.h>
#include<stack>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<cctype>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<cstring>
using namespace std;
const int N = 1001;
vector<int> v[N];// 路径
vector<int> res;// 结果
int inDegree[N];// 入度数组
int n, m;
int main() {
cin >> n >> m;
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
v[a].push_back(b);
inDegree[b]++;// 入度加
}
int k;
cin >> k;
for (int t = 0; t < k; t++) {
vector<int> vv;
int inDegreeDup[n];
for (int i = 1; i <= n; i++) {
inDegreeDup[i] = inDegree[i];// 复制入度数组
}
for (int i = 0; i < n; i++) {
int x;
cin >> x;
vv.push_back(x);
}
int num = 0;
queue<int> qu;
bool flag = true;
for (int i = 0; i < n; i++) {
if (inDegreeDup[vv[i]] == 0) {//如果入度是 0,去除该点的所有路径,并且让入度减减
for (int j = 0; j < v[vv[i]].size(); j++) {
inDegreeDup[v[vv[i]][j]]--;
}
} else {// 如果不是 零, 说明不是拓补,直接 break 即可
flag = false;
break;
}
}
if (!flag) {
res.push_back(t);
}
}
for (int i = 0; i < res.size(); i++) {
if (!i) {
cout << res[i];
} else {
cout << " " << res[i];
}
}
return 0;
}