【拓扑序列】师徒关系

(正在尝试使用标准目录)

【拓扑】师徒关系

一道C++编程问题。

题目大意

在学习圈中,总会有人互相帮助。如果一个人帮助了另一个人,我们称帮助者被帮助者的师傅,被帮助者帮助者的徒弟。一个人可能会有多个师傅,也可能会有多个徒弟。师徒关系可能会在几个人之间继承,如 a a a b b b的师傅, b b b c c c的师傅,则 a a a也是 c c c的师傅。

如果一个人同时是另一个人的师傅和徒弟,那么这两人在学习圈的师徒关系就是不合法的。例如 a a a b b b的师傅, b b b c c c的师傅, c c c a a a的师傅,则 a 、 b 、 c a、b、c abc之间的关系不合法。

现在题目会输入几组学习圈的师徒系统,请你判断每一组数据里是否存在不合法的关系。

输入描述

输入多组数据,对于每一组数据,第一行是两个整数 n n n m m m ( 2 < = n , m < = 100 ) (2<=n,m<=100) (2<=n,m<=100),表示 n n n个人之间有 m m m组师徒。接下来 m m m行,每一行是两个整数 x x x y y y ( 0 < = x , y < n ) (0<=x,y<n) (0<=x,y<n),表示 x x x y y y的师傅。所有数据输入完毕后,输入 ( 0 , 0 ) (0,0) (0,0)表示结束。

输出描述

对于每一组数据,输出YESNO,表示数据中师徒关系是否全部合法。

数据样例

输入

3 2
0 1
1 2

2 2
0 1
1 0

0 0

输出

YES
NO

解题思路

很简单的一道题,我们可以把师徒关系抽象成有向图图象,把人看成图中的点,师徒关系是图中的边。这样,就可以用拓扑排序的理论来解决这道题。合法的师徒关系一定是一条路有尽头,永远不会出现回路。可以用宽搜来做这道题。

AC代码

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,a[1005][1005],p[100005];
//n和m存数据量,x和y用于输入,a[][]存师徒关系,p[]存每人的师傅有几人
bool bfs(){//此函数用于遍历每一组数据
	int sum=0,t;
	queue<int> q;
	for(int i=0;i<n;i++) if(p[i]==0) q.push(i);
	//将没有师傅的人入队,这些人可以作为师傅进入下一轮筛选
	while(!q.empty()){//开始深搜
		t=q.front(),sum++;//sum记录出队次数
		for(int i=0;i<n;i++) if(a[t][i]){//将出队的人的所有徒弟的师傅数量-1
			p[i]--;
			if(p[i]==0) q.push(i);//将没有师傅的人入队
		}
	}
	return sum==n;//如果队列中出现了回路,肯定会有人无法出队,所以出队次数不等于总人数
}
int main(){
	while(cin>>n>>m){
		if(!n&&!m) break;//判断结束
		memset(a,0,sizeof(a));
		memset(p,0,sizeof(p));//每组数据前清空数组
		for(int i=1;i<=m;i++){
			cin>>x>>y;//依次输入关系
			p[y]+=(a[x][y]==0),a[x][y]=1;//记录两人关系和徒弟的师傅数量
		}
		if(f()) cout<<"YES\n";
		else cout<<"NO\n";//判断输出,记得换行
	}
	return 0;
}

感谢观看

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值