原题目: 1146 Topological Order (25 分).
题意
给出有向图的顶点数N(1-N)和有向边数M,以及每条弧的狐尾和狐头。
① 判断所给序列是否为符合该有向图的拓扑排序,
② 输出非拓扑序列的序列序号(从0开始)。
分析
- 存储:① 用 邻接表v 存储有向图(即每个顶点的所有入边);② 用数组 in 记录每个顶点的入度。
- 判断拓扑序列:遍历所给序列,① 拓扑序列(未判断部分)的第一个顶点的入度总是为0,即若第一个顶点入度非0则非拓扑序列;②** 遍历过的顶点在图中删去**——即该顶点所指向的所有结点的入度-1。
知识点
- 有向图的存储——邻接表,即按顶点存储其所有入边。
- 拓扑序列——① 为了方便判断,会记录每个顶点的入度;② 第一个顶点入度总是0;③ 删去顶点——该顶点所指向的所有结点的入度-1。
CODE
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, m, a, b, k, flag = 0, in[1010];
vector<int> v[1010];
cin >> n >> m;
for ( int i=0; i<m; i++ ){
cin >> a >> b;
v[a].push_back(b); //邻接表存储有向图(该顶点的所有出边)
in[b]++; //计算每个顶点的入度
}
cin >> k;
for ( int i=0; i<k; i++ ){
int judge = 1; //假设是拓扑序列
vector<int> tin(in, in+n+1); //用in[]初始化tin,其tin.size()=n+1
for ( int j=0; j<n; j++ ){
cin >> a;
if ( tin[a]!=0 ) judge = 0; //顶点入度非0则非拓扑序列
for ( int it:v[a] ) tin[it]--; //将扫描过的序列点在图中删去,即将其指向的所有结点的入度-1
//遍历数组v[a],每次都用it来接收
}
if ( judge==1 ) continue;
printf("%s%d", flag==1 ? " " : "", i);
flag = 1; //控制输出
}
return 0;
}