HDU - 3342 Legal or Not(拓扑排序板题)

该博客探讨了一个QQ群中的师徒关系问题,将其转化为图论中的有向无环图(DAG)判断。通过拓扑排序的方法,解决是否存在师徒关系形成的环状结构。博客提供了输入输出样例,并给出了问题解决方案。
摘要由CSDN通过智能技术生成
Description

在一个 qq 群里有着许多师徒关系,如 A 是 B 的师父,同时 B
是 A 的徒弟,一个师父可能有许多徒弟,一个徒弟也可能会有许多不同的师父。
输入给出该群里所有的师徒关系,问是否存在这样一种非法的情况:以三个人为
例,即 A 是 B 的师父,B 是 C 的师父,C 又反过来是 A 的师父。若我们将该群
里的所有人都抽象成图上的结点,将所有的师徒关系都抽象成有向边(由师父指
向徒弟),该实际问题就转化 为一个数学问题——该图上是否存在一个环,即判
断该 图是否为有向无环图。

Input

给定N个节点,M个边(2 <= N, M <= 100).N = 0.结束输入。

Output

输出是否有环。

Sample Input

3 2
0 1
1 2
2 2
0 1
1 0
0 0

Sample Output

YES
NO

Solution

拓扑排序板题。

#include <stdio.h>
#include <vector>
#include <queue>
using namespace std;
vector<int> edge[101]; //邻接链表,因为边不存在权值,只需保存与其邻接的结点编号即可, 所以vector中的元素为int
queue<int> Q;          //保存入度为0的结点的队列
int main()
{
    // freopen("in.txt", "r", stdin);
    int inDegree[101]; //统计每个结点的入度
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF)
    {
        if (n == 0 && m == 0)
            break;
        for (int i = 0; i < n; i++)
        {                    //初始化所有结点,注意本题结 点编号由0到n-1
            inDegree[i] = 0; //初始化入度信息,所有结点入度均为0
            edge[i].clear(); //清空邻接链表,使用clear()效率高,15ms AC
            // vector<int>().swap(edge[i]);//使用回收内存方法效率低,30ms AC
        }
        while (m--)
        {
            int a, b;
            scanf("%d%d", &a, &b); //读入一条由a指向b的有向边
            inDegree[b]++;         //又出现了一条弧头指向b的边,累加结点b的入度
            edge[a].push_back(b);  //将b加入a的邻接链表
        }
        while (Q.empty() == false)
            Q.pop(); //若队列非空,则一直弹出队头元素,该操作的目的 为清空队列中所有的元素(可能为上一组测试数据中遗留的数据)
        for (int i = 0; i < n; i++)
        { //统计所有结点的入度
            if (inDegree[i] == 0)
                Q.push(i); //若结点入度为0,则将其放入队列
        }
        int cnt = 0; //计数器,初始值为0,用于累加已经确定拓扑序列的结点个数
        while (Q.empty() == false)
        {                         //当队列中入度为0的结点未被取完时,重复
            int nowP = Q.front(); //读出队头结点编号,本例不需要求出确定的拓扑序列,故不做处理;
                                  // 若要求求出确定的拓扑次序, 则将该结点紧接着放在已经确定的拓扑序列之后
            Q.pop();              //弹出对头元素
            cnt++;                //被确定的结点个数加一
            for (int i = 0; i < edge[nowP].size(); i++)
            {                              //将该结点以及以其为弧尾的所有边去除
                inDegree[edge[nowP][i]]--; //去除某条边后,该边所指后继结点入度减 一
                if (inDegree[edge[nowP][i]] == 0)
                {                          //若该结点入度变为0
                    Q.push(edge[nowP][i]); //将其放入队列当中
                }
            }
        }
        if (cnt == n)
            puts("YES");
        // printf("YES\n"); //若所有结点都能被确定拓扑序列,则原图为有向无环图,puts() 15ms AC,printf() 30ms AC
        else
            puts("NO");
        // printf("NO\n"); //否则,原图为非有向无环图
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值