算法(二) -- 拓扑排序

本文介绍了一个基于拓扑排序算法的问题——判断给定的师徒关系是否合法,即是否存在非法的循环关系。通过使用邻接矩阵和拓扑排序,我们可以有效地判断关系的合法性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Legal or Not

http://acm.hdu.edu.cn/showproblem.php?pid=3342
1、问题描述
ACM-DIY是一个庞大的QQ群,许多优秀的acmers聚集在一起。它是如此和谐,就像一个大家庭。每天,许多“圣牛”像hh、HH、AC、ZT、lcc、BF、Qinz等在网上聊天交流想法。当有人有问题的时候,许多热心的大牛会过来帮忙,比如Lost。然后被帮助的人会叫Lost“主人”,Lost会有一个美好的“学徒”。渐渐地,有许多对“师傅和徒弟”。但是问题出现了:有太多的主人和太多的学徒,我们怎么知道它是否合法?
我们都知道一个师傅可以有很多徒弟,一个徒弟也可以有很多师傅,这是合法的。然而,有些大牛并不诚实,他们有非法关系。以HH和3xian为例,HH是3xian的主人,同时,3xian是HH的主人,这是非常非法的!为了避免这种情况,请帮助我们判断他们的关系是否合法。
请注意,“师徒”关系是可传递的。这意味着如果甲是乙的主人,乙是丙的主人,那么甲就是丙的主人
2、 输入
输入由几个测试用例组成。对于每种情况,第一行包含两个整数,N(要测试的成员)和M(要测试的关系)(2 <= N,M <= 100)。然后是M行,每一行包含一对(x,y),这意味着x是y的主人,y是x的徒弟。输入端接N = 0。
为了简单起见,我们给每个人一个数字(0,1,2,…,N-1)。我们用他们的号码代替他们的名字。
3、输出
对于每个测试用例,在一行中打印出混乱关系的判断。
如果合法,输出“Yes”,否则输出“No”
4、 样例输入
3 2
0 1
1 2
2 2
0 1
1 0
0 0
5、 样例输出
YES
NO
6、 问题分析
通过题目我们可以很清楚的知道其实要求很简单,就是不能存在环,因此我们要做的就是要判断给出的数据中是否存在环,可用邻接矩阵来进行拓扑排序,然后得出结果。
邻接矩阵:
逻辑结构分为两部分:V和E集合,其中,V是顶点,E是边。因此,用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵。
拓扑排序:
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
7、 测试示例
输入:
3 2
0 1
1 2
2 2
0 1
1 0
0 0
输出:
YES
NO
8、AC代码:

#include<stdio.h>
#include<string.h>
int uni[1001][1001],inp[1001];
int main(){
    int a,b,n,m,i,j;
    while(scanf("%d%d",&n,&m)=EOF&&n){
        memset (inp,0,sizeof(inp));
        memset (uni,0,sizeof(uni));
        for(i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            uni[a][b] = 1;       //标记连通点
        }
        for(i=0;i<n;i++)
        	for(j=0;j<n;j++)  
       			 if(uni[i][j])
       			 	inp[j]++;  //计算点j入度
        	int  k = 0;
        	while(1){       //拓扑排序
            int flag = 0;
            for(i=0;i<n;i++){
                if(inp[i]==0){  //入度为0时
                    flag =1;
                    inp[i] = -1;  //销毁此点
                    k++;
                    for(j = 0;j < n;j++){
                        if(uni[i][j]){  //找到连接i的点
                            inp[j]--;    //因为i点已被销毁,所以连接j点的入度减一
                        }
                    } 
                break;
                }
            }
            if(flag == 0||k ==n)break; //k=n为合法关系
        }
    if(k==n)printf("YES\n");
    else printf("NO\n");
    }
  return 0;
  }

9、 解题备注
此题为简单的拓扑排序题,如果可以通过拓扑排序输出所有结果,则说明没有环,即关系合法,反正则不合法。
10、运行结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值