题目链接在这里:Problem - D - Codeforces
拓扑排序是个好东西,常用在途中各个点之间有先后顺序的问题的求解,同时在处理环问题中也有应用。在处理与环有关的问题时可以直接去掉与环无关的点,相当于在不断的简化这个图,不断通过入度为0的点删根节点,直到没有入度为0 的点,剩下的点全在环里面。删边的话直接将边所指向点的入度减一就行了。
以前遇到环的问题一般想的是tarjan,不过tarjan需要遍历边,而且删边的话只能对每一条边进行操作,需要枚举边,这里边数远远大于点数,所以用tarjan是不合适的。点的数量级小的话,用拓扑排序判断环是一个很好的选择。
1 #include "bits/stdc++.h" 2 using namespace std; 3 const int MAX=505; 4 int n,m; 5 int a[MAX][MAX]; 6 int in[MAX],ii[MAX]; 7 bool topu(){ 8 int i,j,zt,an=0; 9 queue <int> q; 10 while (!q.empty()) q.pop(); 11 for (i=1;i<=n;i++) 12 if (ii[i]==0) 13 q.push(i),an++; 14 while (!q.empty()){ 15 zt=q.front();q.pop(); 16 for (i=1;i<=n;i++) 17 if (a[zt][i] && ii[i]){ 18 ii[i]--; 19 if (ii[i]==0) q.push(i),an++; 20 } 21 } 22 return (an==n); 23 } 24 int main(){ 25 freopen ("d.in","r",stdin); 26 freopen ("d.out","w",stdout); 27 int i,j,u,v; 28 scanf("%d%d",&n,&m); 29 memset(a,0,sizeof(a)); 30 memset(in,0,sizeof(in)); 31 for (i=1;i<=m;i++){ 32 scanf("%d%d",&u,&v); 33 a[u][v]=1; 34 in[v]++; 35 } 36 for (i=1;i<=n;i++){ 37 for (j=1;j<=n;j++) ii[j]=in[j]; 38 ii[i]--; 39 if (topu()){ 40 printf("YES"); 41 return 0; 42 } 43 } 44 printf("NO"); 45 return 0; 46 }