zoukankan      html  css  js  c++  java
  • ACwing848. 有向图的拓扑序列

    题目

    给定一个n个点m条边的有向图,点的编号是1到n,图中可能存在重边和自环。

    请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出-1。

    若一个由图中所有点构成的序列A满足:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。

    输入格式

    第一行包含两个整数n和m

    接下来m行,每行包含两个整数x和y,表示存在一条从点x到点y的有向边(x, y)。

    输出格式

    共一行,如果存在拓扑序列,则输出任意一个合法的拓扑序列即可。

    否则输出-1。

    数据范围

    1n,m105

    输入样例:
    3 3
    1 2
    2 3
    1 3
    
    输出样例:
    1 2 3
    

    分析

    拓扑排序,就是找入度为0的点入队列,弹出队列后将其出边连接点的入度减一。写法和BFS的模板差不多,因为都是对队列弹出结点的出边的结点操作。区别:队列弹出结点信息要记录,因为弹出结点的顺就是拓扑排序顺序。可以开一个数组记录弹出结点的信息,或者用数组模拟队列。

    整体思路:

    1.先找到所有入度为0 的结点入队列q

    2.弹出队头元素q.front(),并记录这个结点

    3.找到这个结点的所有出边的结点,使这些结点的入度减一,若入度减一后为0,入队列。

    4.循环2,3步直到队列为空

    代码

    用 ans存放拓扑排序结果

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<queue>
     5 using namespace std;
     6 
     7 const int N = 100010;
     8 int h[N],e[N],ne[N],idx;
     9 int n,m;
    10 int d[N];//存放每个结点的入度
    11 vector<int>ans;//记录拓扑排序结果
    12 
    13 void add(int a,int b){
    14     e[idx] = b,ne[idx] = h[a],h[a] = idx++;
    15 }
    16 
    17 void topsort(){
    18     queue<int>q;
    19     //寻找度为0的点
    20     for(int i = 1;i <=n;i++){
    21         if(d[i] == 0){
    22             q.push(i);
    23         }
    24     }
    25     
    26     while(!q.empty()){
    27         int t = q.front();ans.push_back(t);
    28         q.pop();
    29         //将该元素出边的结点入度减一
    30         for(int i = h[t];i!=-1;i = ne[i]){
    31             int j = e[i];
    32             d[j]--; //删掉边,入度减一
    33             if(d[j] == 0){
    34                 q.push(j);
    35             }
    36         }
    37     }
    38     
    39 }
    40 
    41 int main(){
    42     scanf("%d%d",&n,&m);
    43     memset(h,-1,sizeof(h));
    44     for(int i = 0;i < m;i++){
    45         int a,b;
    46         scanf("%d%d",&a,&b);
    47         add(a,b);
    48         d[b]++; //b的入度加1
    49     }
    50     topsort();
    51     if(ans.size()!=n){
    52         cout<<"-1";
    53     }else{
    54         for(auto it:ans) cout<<it<<" ";
    55     }
    56     return 0;
    57 }

    用数组模拟队列,这样会保留弹出结点信息

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 
     6 const int N = 100010;
     7 int h[N],e[N],ne[N],idx;
     8 int n,m;
     9 int d[N];//存放每个结点的入度
    10 int q[N]; //用数组模拟队列
    11 
    12 void add(int a,int b){
    13     e[idx] = b,ne[idx] = h[a],h[a] = idx++;
    14 }
    15 
    16 bool topsort(){
    17     int hh = 0, tt = -1;  //定义对头,队尾
    18     //寻找度为0的点
    19     for(int i = 1;i <=n;i++){
    20         if(d[i] == 0){
    21             q[++tt] = i;  //入队
    22         }
    23     }
    24     
    25     while(hh <= tt){
    26         int t = q[hh++];
    27         
    28         //将该元素出边的结点入度减一
    29         for(int i = h[t];i!=-1;i = ne[i]){
    30             int j = e[i];
    31             d[j]--; //删掉边,入度减一
    32             if(d[j] == 0){
    33                 q[++tt] = j;
    34             }
    35         }
    36     }
    37     return tt == n-1; //是否队列为n个点,来判断是否存在拓扑序列
    38     
    39 }
    40 
    41 int main(){
    42     scanf("%d%d",&n,&m);
    43     memset(h,-1,sizeof(h));
    44     for(int i = 0;i < m;i++){
    45         int a,b;
    46         scanf("%d%d",&a,&b);
    47         add(a,b);
    48         d[b]++; //b的入度加1
    49     }
    50    if(topsort()){
    51        for(int i = 0;i < n;i++)
    52         printf("%d ",q[i]);
    53    }else{
    54        printf("-1");
    55    }
    56     return 0;
    57 }
  • 相关阅读:
    自定义组件要加@click方法
    绑定样式
    647. Palindromic Substrings
    215. Kth Largest Element in an Array
    448. Find All Numbers Disappeared in an Array
    287. Find the Duplicate Number
    283. Move Zeroes
    234. Palindrome Linked List
    202. Happy Number
    217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/fresh-coder/p/14441860.html
Copyright © 2011-2022 走看看