九度1448 拓扑排序

题目:
输入编号为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 }

 

转载于:https://www.cnblogs.com/songshu-gancuimian/p/6720034.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值