题目:
输入编号为0,1,2,...,(N-1)的N个点间的M条有向边(2<=N,M<=100),判断是不是有向无环图。
知识回顾:
1.有a条边指向某点,则该点的“入度”为a;从某点发出的边有b条,则该点的出度为b。
2.拓扑排序:找出所有点的一种排序x1,x2,...,xi,...xj,...,xN,使该序列中任意前后两点xi和xj,不会出现该情况:从xj出 发,按有向边,可到达xi。
3.拓扑排序算法:找到入度为0的一点,作为第一点,然后擦除该点,以及从该点出发的边。
在图中再找入度为0的点,作为第二点,然后擦除该点,以及从该点出发的边。
如此重复该步骤,直到所有点都加入序列,则说明该图为有向无环图。
过程中,如果点还没全加入序列,但已经没有入度为0的点,则说明该图为有向有环图。
思路:
判断是否为有向无环图,就想到用拓扑排序。
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <queue> 4 #include <vector> 5 #include <cstring> 6 using namespace std; 7 8 queue<int> que; //队列,存所有入度为0的点 9 vector<int> vec[101]; //邻接链表,存有向图 10 int inDegree[101]; //存点的入度(其中‘-1‘表示该点已在拓扑序列中,或已在队列中) 11 int N,M; //N个点,M条边 12 13 //让入度为0的点入队 14 void intoQueue(); 15 //读取某点的边链表,并让相应点的入度减1,同时清除该点的边链表 16 void readEdgeLink(int a); 17 //判断图是不是一个无环图 18 bool isNoCircle(); 19 20 //主函数 21 int main(){ 22 int i,a,b; 23 while(scanf("%d %d",&N,&M)!=EOF && (N||M)){ //输入N和M(如果N和M都为0则跳出循环) 24 memset(inDegree,0,101*sizeof(int)); //初始化入度:都为0 25 for(i=0;i<M;i++){ //输入M条边,并存入邻接链表 26 scanf("%d %d",&a,&b); //输入边a->b 27 vec[a].push_back(b); //把边a->b存入邻接链表 28 inDegree[b]++; //b点的入度加1 29 } 30 31 intoQueue(); //让入度为0的点入队 32 while(!que.empty()){ //队未空,还有入度为0的点,继续循环 33 a=que.front(); //出队 34 que.pop(); 35 readEdgeLink(a); //读取a点的边链表,并让相应点的入度减1,同时清除点a的边链表 36 intoQueue(); //让入度为0的点入队 37 } 38 39 if(isNoCircle()) //所有点都加入拓扑序列 40 printf("YES\n"); //该图是有向无环图 41 else { //有点没加入拓扑序列 42 printf("NO\n"); //该图是有向有环图 43 for(i=0;i<N;i++) //循环清除边边链表,以便下个测试使用 44 vec[i].clear(); 45 } 46 } 47 return 0; 48 } 49 50 //让入度为0的点入队 51 void intoQueue(){ 52 int i; 53 for(i=0;i<N;i++){ //遍历N个点 54 if(inDegree[i]==0){ //若某点的入度为0 55 inDegree[i]=-1; //将其入度改为-1,表示该点已被处理过(已在拓扑序列中,或已在队列中) 56 que.push(i); //该点入队 57 } 58 } 59 } 60 61 //读取某点的边链表,并让相应点的入度减1,同时清除该点的边链表 62 void readEdgeLink(int a){ 63 int b; 64 for(int i=0;i<vec[a].size();i++){ //循环读取a点开头的每条边 65 b=vec[a][i]; //读出边a->b 66 inDegree[b]--; //点b的入度减1 67 } 68 vec[a].clear(); //清除点a的边链表 69 } 70 71 //判断图是不是一个无环图 72 bool isNoCircle(){ 73 for(int i=0;i<N;i++){ //遍历N个点 74 if(inDegree[i]!=-1){ //如果还有入度不为-1的点 75 return false; //表明拓扑排序结束时还有点没加入序列,但已没有入度为0的点,即该图有环 76 } 77 } 78 return true; //表明所有点都已经加入拓扑序列,图是无环图 79 }
原文:http://www.cnblogs.com/songshu-gancuimian/p/6720034.html