HDU 3342 Legal or Not (图是否有环)
题意:
给出n个人的师徒关系,如有 a是b的师傅,b是c的师傅,c是a的师傅,这样则不合法,输出NO,否则输出YES。
思路:
每段关系可以看成一条有向边,从师傅指向徒弟,那么徒弟的徒子徒孙都不可能再指向其师傅或自己,所以不可能构成环。
两种方法 :
1,用拓扑的方法,每次去掉一个入度为0的点,全部点都去掉就是合法的。(下面代码用此法)
2,用深搜,记录路径,当搜到走过的路径上的点就是有环。每个点都可能重复搜多次,因为这不是树。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=105; 4 int n, m; 5 bool vis[N]; //遍历 6 int num[N]; //入度数 7 vector< vector<int> > vect; 8 deque<int> que; 9 10 int cal() 11 { 12 que.clear(); 13 for(int i=0; i<n; i++) if(!num[i]) que.push_back(i); //挑出入度为0的 14 15 while(!que.empty()) 16 { 17 int p=que.front(); 18 que.pop_front(); 19 vis[p]=true; 20 for(int i=0,q; i<vect[p].size(); i++ ) 21 { 22 q=vect[p][i]; 23 num[q]--; //这条边删掉 24 if(!num[q]) que.push_back(q); 25 } 26 } 27 28 for(int i=0; i<n; i++) if(!vis[i]) return 0; 29 return 1; 30 } 31 32 int main() 33 { 34 int a, b; 35 // freopen("input.txt", "r", stdin); 36 while(scanf("%d%d",&n,&m),n) 37 { 38 vect.clear(); 39 vect.resize(n); 40 memset(num, 0, sizeof(num)); 41 memset(vis,0,sizeof(vis)); 42 for(int i=0; i<m; i++) 43 { 44 scanf("%d%d",&a,&b); 45 vect[a].push_back(b); //有向图 46 num[b]++; 47 } 48 49 if(cal()) printf("YES\n"); 50 else printf("NO\n"); 51 52 } 53 return 0; 54 }