✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:PAT题解集合
📝原题地址:题目详情 - 1146 Topological Order (pintia.cn)
🔑中文翻译:拓扑顺序
📣专栏定位:为想考甲级PAT的小伙伴整理常考算法题解,祝大家都能取得满分!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
1146 Topological Order
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
题意
给定一个有向图,并给定多个序列,需要我们判断这些序列是否是拓扑序列,将不是拓扑序列的询问编号输出,询问编号从 0
开始。
拿题目样例来看,序列 [5 2 1 6 3 2]
之所以不是拓扑序列,是因为其中 2->1
方向反了。
图中只有 1->2
的边但没有 2->1
的边,不能出现逆向边,也就是每条边的前面那个点在序列中的位置必须在后面那个点的位置之前。
思路
我们可以通过记录给定序列每个元素对应的下标,然后去判断每条边的两个端点的下标大小,如果是拓扑序列,则每条边 a->b
中 a
在序列中的下标必须比 b
在序列中的下标小,即 a
在序列中的位置必须在 b
之前,否则就不是一个拓扑序列。
假设还是样例中的那张图,现在给定一个序列 [5 2 3 6 4 1]
,可以找到一条边 1->2
,发现 1
在序列中的第 6
位,而 2
却在第 2
位,即 1
出现在了 2
的后面,所以该序列不是拓扑序列。
另外需要注意的是,输出的询问编号是从 0
开始,并且输出的末尾不能出现空格。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 10010;
struct Edge {
int a, b;
}e[M];
int p[N];
int main()
{
int n, m;
cin >> n >> m;
//输入每条有向边
for (int i = 0; i < m; i++) cin >> e[i].a >> e[i].b;
//开始查询
bool is_first = true; //输出行末不能有空格
int k;
cin >> k;
for (int i = 0; i < k; i++)
{
//输入每个序列
for (int j = 1; j <= n; j++)
{
int x;
cin >> x;
p[x] = j; //记录每个点所在序列下标
}
//遍历每条边,判断是否都满足拓扑序列规则
bool success = true;
for (int i = 0; i < m; i++)
if (p[e[i].a] > p[e[i].b])
{
success = false;
break;
}
//输出不是拓扑序列的询问编号
if (!success)
{
if (is_first) is_first = false;
else cout << " ";
cout << i;
}
}
cout << endl;
return 0;
}