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、运行结果