📜  门|门 CS 1999 |问题 7(1)

📅  最后修改于: 2023-12-03 15:28:47.893000             🧑  作者: Mango

门|门 CS 1999 |问题 7

该问题是一道典型的图论问题,需要我们对一张有向图进行拓扑排序,判断其是否存在环。

问题描述

给定一个n个节点m条边的有向图,求该图是否存在环。如果存在环,输出 YES 否则输出 NO。

解题思路

该问题可以利用拓扑排序来解决。拓扑排序是一种对有向无环图(DAG)进行排序的方法。

  1. 统计每个节点的入度,即有多少个节点指向它;
  2. 将入度为0的节点加入队列,作为拓扑序列的起始节点;
  3. 取出队列头部节点,遍历其所有出边的终点节点,在其终点节点的入度中减去1;
  4. 如果有终点节点其入度变成0,那么将该终点节点加入队列
  5. 重复3、4步骤,直到所有节点都被遍历过,或没有入度为0的节点。

如果没有完成所有节点的遍历,那么该图一定存在环。

代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=200010;
int n,m;
int p[N],ne[M],e[M],idx;
int din[N];//入度
int q[N],hh,tt;

void add(int a,int b)
{
    e[idx]=b,ne[idx]=p[a],p[a]=idx++,din[b]++;
}

bool topsort()
{
    hh=0,tt=-1;
    for(int i=1;i<=n;i++)
    {
        if(din[i]==0) q[++tt]=i;
    }

    while(hh<=tt)
    {
        int t=q[hh++];
        for(int i=p[t];i!=-1;i=ne[i])
        {
            int j=e[i];
            din[j]--;
            if(din[j]==0) q[++tt]=j;
        }
    }

    return tt==n-1;
}

int main()
{
    memset(p,-1,sizeof p);
    cin>>n>>m;
    while(m--)
    {
        int a,b;
        cin>>a>>b;
        add(a,b);
    }

    if(topsort()) puts("No");
    else puts("Yes");

    return 0;
}
时间复杂度

该算法的时间复杂度为O(n+m),其中n代表点数,m代表边数。

总结

本题是一道典型的图论问题,利用拓扑排序可以解决。对于初学者来说是一道比较好的练手题目。