• 拓扑排序板子练习


    目录

    一、前言

    二、拓扑排序板子

    三、题目:拓扑顺序

    1、上链接

    2、基本思路

    3、代码

    (1)C++(AC)

    (2)python(AC)

    四、题目:可达性统计

    1、上链接

    2、基本思路

    3、代码

    (1)C++(AC)

    (2)python


    一、前言

    拓扑排序想必不用再多介绍了,下面来看看拓扑排序的一个板子(遍历某一个点的所有边),并做两道拓扑排序相关的例题。

    二、拓扑排序板子

    直接看代码。

    1. #include
    2. #include // 拓扑排序经常需要用到队列
    3. #include
    4. using namespace std;
    5. const int N=10010;
    6. int n,m; //顶点数,边数
    7. int e[N],h[N],ne[N],idx; //某边终点、以某点为起点的第一条边、以某点为起点的下一条边、第idx条边
    8. int degree[N]; //存储对应点的入度
    9. void Add(int a,int b){
    10. e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    11. }
    12. void topsort(){
    13. queue<int> q;
    14. for(int i=1;i<=n;++i)
    15. if(!degree[i])
    16. q.push(i);
    17. while(!q.empty()){
    18. int t=q.front();
    19. q.pop();
    20. cout<" ";
    21. for(int i=h[t];~i;i=ne[i]){
    22. int j=e[i];
    23. if(--degree[j]==0)
    24. q.push(j);
    25. }
    26. }
    27. cout<
    28. }
    29. int main(){
    30. cin>>n>>m;
    31. memset(h,-1,sizeof h); //所以~i能结束
    32. for(int i=0;i
    33. int a,b;
    34. cin>>a>>b;
    35. Add(a,b); //把当前的边存起来
    36. degree[b]++;
    37. }
    38. topsort();
    39. return 0;
    40. }

    三、题目:拓扑顺序

    1、上链接

    1639. 拓扑顺序 - AcWing题库

    2、基本思路

    对拓扑排序的板子进行相应的修改即可。

    3、代码

    (1)C++(AC)

    1. #include
    2. #include // 拓扑排序经常需要用到队列
    3. #include
    4. using namespace std;
    5. const int N=10010;
    6. const int K=110;
    7. int n,m,k; //顶点数,边数
    8. int e[N],h[N],ne[N],idx; //某边终点、以某点为起点的第一条边、以某点为起点的下一条边、第idx条边
    9. int degree[N]; //存储对应点的入度
    10. int ask[N],flg[K],d[N];
    11. void Add(int a,int b){
    12. e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    13. }
    14. int topsort(){
    15. for(int i=1;i<=n;++i){
    16. if(d[ask[i]])
    17. return 0;
    18. for(int j=h[ask[i]];~j;j=ne[j]){
    19. d[e[j]]--;
    20. }
    21. }
    22. return 1;
    23. }
    24. int main(){
    25. cin>>n>>m;
    26. memset(h,-1,sizeof h);
    27. for(int i=0;i
    28. int a,b;
    29. cin>>a>>b;
    30. Add(a,b); //把当前的边存起来
    31. degree[b]++;
    32. }
    33. cin>>k;
    34. for(int i=0;i
    35. for(int j=1;j<=n;j++){
    36. cin>>ask[j];
    37. d[ask[j]]=degree[ask[j]];
    38. //或这样写,都是一样的
    39. // d[j] = degree[j]
    40. }
    41. if(topsort())
    42. flg[i]=1;
    43. else
    44. flg[i]=0;
    45. }
    46. int i=0;
    47. for(i=0;i
    48. if(!flg[i]){
    49. cout<
    50. break;
    51. }
    52. }
    53. i++;
    54. for(;i
    55. if(!flg[i])
    56. cout<<" "<
    57. }
    58. cout<
    59. return 0;
    60. }

    (2)python(AC)

    1. N=10010
    2. e=[0]*N
    3. ne=[0]*N
    4. h=[-1]*N
    5. idx=0
    6. degree=[0]*N
    7. d=[0]*N
    8. ask=[0]*N
    9. flg=[0]*110
    10. def Add(a,b):
    11. global idx
    12. e[idx]=b
    13. ne[idx]=h[a]
    14. h[a]=idx
    15. idx=idx+1
    16. def topsort():
    17. for i in range(1,n+1):
    18. if d[ask[i]]!=0:
    19. return 0
    20. j=h[ask[i]]
    21. while ~j:
    22. d[e[j]]-=1
    23. j=ne[j]
    24. return 1
    25. n,m=map(int,input().split())
    26. for i in range(m):
    27. a,b=map(int,input().split())
    28. Add(a,b)
    29. degree[b]+=1
    30. k=int(input())
    31. for i in range(k):
    32. lines=list(map(int,input().split()))
    33. for j in range(1,n+1):
    34. ask[j]=lines[j-1]
    35. d[ask[j]]=degree[ask[j]]
    36. if topsort():
    37. flg[i]=1
    38. else:
    39. flg[i]=0
    40. ## print(flg[i],end="@")
    41. ## print("")
    42. c=0
    43. for i in range(k):
    44. if c==0 and flg[i]==0:
    45. print(i,end="")
    46. c=1
    47. elif flg[i]==0:
    48. print(" {}".format(i),end="")
    49. print("")

    四、题目:可达性统计

    1、上链接

    164. 可达性统计 - AcWing题库

    2、基本思路

    对拓扑排序的板子进行相应的修改即可。

    3、代码

    (1)C++(AC)

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. const int N=30010;
    7. int n,m;
    8. int e[N],ne[N],h[N],idx;
    9. int degree[N];
    10. int seq[N];
    11. bitset f[N];
    12. void Add(int a,int b){
    13. e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    14. }
    15. void topsort(){
    16. queue<int> q;
    17. for(int i=1;i<=n;++i)
    18. if(degree[i]==0)
    19. q.push(i);
    20. int k=0;
    21. while(!q.empty()){
    22. int t=q.front();
    23. q.pop();
    24. seq[k++]=t;
    25. for(int i=h[t];~i;i=ne[i]){
    26. int j=e[i];
    27. if(--degree[j]==0)
    28. q.push(j);
    29. }
    30. }
    31. }
    32. int main(){
    33. cin>>n>>m;
    34. memset(h,-1,sizeof h);
    35. for(int i=0;i
    36. int a,b;
    37. cin>>a>>b;
    38. Add(a,b);
    39. degree[b]++;
    40. }
    41. topsort();
    42. for(int i=n-1;i>=0;i--){
    43. int j=seq[i];
    44. f[j][j]=1;
    45. for(int p=h[j];~p;p=ne[p]){
    46. f[j]|=f[e[p]];
    47. }
    48. }
    49. for(int i=1;i<=n;++i){
    50. cout<count()<
    51. }
    52. return 0;
    53. }

    bitset用来处理二进制位非常方便。头文件是 #include,bitset可能在PAT、蓝桥OJ中不常用,但是在LeetCode OJ中经常用到~而且知道 bitset 能简化一些操作,可能一些复杂的问题能够直接用 bitset 就很轻易的解决了。

    bitset的用法随便百度一下就能找到一大堆,这里就不啰嗦了。

    解释一下为什么“ f[j] |= f[e[p]] ”,如下图。(所以序列的遍历方向从后往前)

    (2)python

    我也想写一个python代码,在python中,bitset也确实可以写成一个类来实现,但是这个“类bitset”并不能起到优化空间的作用,该到题的内存会爆。而直接开一个二维列表来处理每个点的可达点数,内存无疑也会爆掉,故python代码我没能写出来。

    稍微算一下题目的空间:

    N和M的最大数值为 30000,即数组最大初始化有 30000 个int。

    开 N^2 大小的空间,就有 9*10^8 个int,我们知道 10^6 个int约等于 4M,则 9*10^8 个int会有 3600M,题目空间限制为 256M。非常遗憾,内存爆了。

    稍微解释一下 “10^6 个int约等于 4M”:

    4M = 1024*4kb = 1024*1024*4byte = 10^6 个int

    以上,拓扑排序

    祝好

     

  • 相关阅读:
    为什么选择虚拟展会展览?了解虚拟展会展览的应用领域
    25、四大函数式接口(消费型接口(Consumer)和供给型接口(Supplier))
    【毕业设计】大数据用户画像分析系统 - 数据分析
    企业电子文档管理系统哪个好?怎么选?
    谈谈系统性能调优中都需要考虑哪些因素
    随着Python越来越火,前景如何?
    C语言:指针的基础详解
    sql update 不更新
    JUC——AQS原理分析
    快速排序及优化
  • 原文地址:https://blog.csdn.net/m0_52711790/article/details/127885290