拓扑排序以前不考,现在考的频率好高。
其实没啥难的,抓住一点:入度为0时,才能被输出(或者被选中,一个意思)。所以要用个int inDegree来维护入度的数量。 当要我们判断一个图能不能是拓扑排序(即没有环),就是看入过队列的节点数是不是就是N。
例题:
判断能不能对某个图做拓扑排序
https://pintia.cn/problem-sets/15/problems/861
大意:给你一个图,让你判断能不能拓扑排序。
输入数据:
输入说明:输入第一行给出子任务数N(≤100),子任务按1~N编号。随后N行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数K,随后给出K个子任务编号,整数之间都用空格分隔。
12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7
输出:
0
代码:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int maxnum = 105;
int N;
vector<int> G[maxnum];
int inDegree[maxnum];
bool Judge()
{
queue<int> Q;
for (int i = 1; i <= N; i++)
if (inDegree[i] == 0)
Q.push(i); //把一开始入度为0的入队
int cnt = 0;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
cnt++; //u加入Top队列
for (int i = 0; i < G[u].size(); i++)
{
int v = G[u][i]; //u后续节点
inDegree[v]--; //更新入度
if (inDegree[v] == 0)
Q.push(v);
}
}
if (cnt == N)
return true;
else return false;
}
int main()
{
cin >> N;
for (int i = 1; i <= N; i++)
{
int num;
cin >> num;
inDegree[i] = num; //存储初始入度
for (int j = 0; j < num; j++)
{
int a;
cin >> a;
G[a].push_back(i);
}
}
cout << Judge();
return 0;
}
判断一个序列是否是拓扑排序的结果序列
输入:
每个输入文件包含一个测试用例。对于每种情况,第一行给出两个正整数N(≤1000),表示图中顶点的数量,M(≤10000)表示有向边的数量。然后有M条线,每条线给出一条边的开始点和结束点。顶点编号从1到n,图后还有一个正整数K(≤100)。然后是K行查询,每一行给出所有顶点的排列。一行中的所有数字都用空格隔开。
6 8
1 2
1 3
5 2
5 4
2 3
2 6
3 4
6 4
5
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
输出:
在一行中打印所有符合“非拓扑顺序”的查询索引。指标从零开始。所有的数字用空格隔开,行首和行尾都不能有多余的空格。很显然,至少有一个答案。
3 4
思路:对于某个序列来说,一个个把数字读进来,然后判断这个数当前的入度是否是0。如果不是0,则说明违反了拓扑排序。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int maxnum = 1005;
const int INF = 99999;
int N, M, K;
vector<int> G[maxnum];
int inDegree[maxnum];
vector<int> res;
int main()
{
cin >> N >> M;
for (int i = 0; i < M; i++)
{
int a, b;
cin >> a >> b;
G[a].push_back(b); //单向图
inDegree[b]++; //b的入度加一
}
cin >> K;
for (int i = 0; i < K; i++)
{
vector<int> in(inDegree,inDegree+N+1); //每次复制出一个入度副本
int judge = 1; //初始默认是拓扑排序
for (int j = 0; j < N; j++)
{
int a; //当前选中的节点
cin >> a;
if (in[a] != 0) //如果当前a的入度不为0,不是top
judge = 0;
for (int k = 0; k < G[a].size(); k++) //更新与当前选中节点有关点的入度
in[G[a][k]]--;
}
if (judge == 0)
res.push_back(i);
}
for (int i = 0; i < res.size(); i++)
{
if (i == 0) cout << res[i];
else cout << " " << res[i];
}
return 0;
}