• (笔记整理未完成)【图论】无向图求割点、割边


    知识点


    一 .  割点

    定义:将该点删去后,新生成的图(不包括删去的顶点)会分为两个或两个以上的不连通子图。


    模板题

    一. 洛谷 P3388 【模板】割点(割顶)

    题目描述

    给出一个 n 个点,m 条边的无向图,求图的割点。

    输入格式

    第一行输入两个正整数 n,m。

    下面 m 行每行输入两个正整数 x,y 表示 x 到 y 有一条边。

    输出格式

    第一行输出割点个数。

    第二行按照节点编号从小到大输出节点,用空格隔开。

    输入输出样例

    输入 #1

    6 7
    1 2
    1 3
    1 4
    2 5
    3 5
    4 5
    5 6

    输出 #1

    1 
    5

    说明/提示

    对于全部数据,1\leqslant n \leqslant 2\times 10^41\leqslant m \leqslant 1 \times 10^5

    点的编号均大于 0 小于等于 n。

    tarjan图不一定联通。


    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. int n,m;
    8. const int maxn=1e7+5;
    9. struct node{
    10. int to,next;
    11. }edge[maxn<<1];
    12. int head[maxn],num=0;
    13. int dfn[maxn],low[maxn],cnt=0,res=0;
    14. bool vis[maxn];
    15. inline int read()
    16. {
    17. int x=0,f=1;
    18. char c=getchar();
    19. while(c<'0'||c>'9')
    20. {
    21. if(c=='-') f=-1;
    22. c=getchar();
    23. }
    24. while(c>='0' && c<='9')
    25. {
    26. x=(x<<3)+(x<<1)+(c^48);
    27. c=getchar();
    28. }
    29. return x*f;
    30. }
    31. inline void write(int x)
    32. {
    33. if(x<0) putchar('-'),x=-x;
    34. if(x>9) write(x/10);
    35. putchar(x%10+'0');
    36. }
    37. inline void add(int u,int v)
    38. {
    39. edge[++num].to=v;
    40. edge[num].next=head[u];
    41. head[u]=num;
    42. }
    43. inline void tarjan(int u,int root)
    44. //u表示当前访问到第u个点,root表示以root为根节点的子树的根
    45. {
    46. dfn[u]=low[u]=++cnt; //记录是第几个搜索到的
    47. int ans=0;
    48. for(int i=head[u];i!=-1;i=edge[i].next)
    49. {
    50. int v=edge[i].to;
    51. if(!dfn[v])
    52. {
    53. tarjan(v,root);
    54. low[u]=min(low[u],low[v]); //更新能到达的最远的根节点
    55. if(low[v]>=dfn[u] && u!=root) vis[u]=1;
    56. /*非根且子树能达到的dfn最小的结点>=自己的节点
    57. 说明它的子树中最早能访问到的结点都比它后访问,此时只要不为根就一定是割点*/
    58. if(u == root) ans++; //如果叶节点刚好可以到达根节点,统计子树的数量
    59. }
    60. low[u]=min(low[u],dfn[v]); //把点u及u的子树可以达到的dfn的最小结点更新
    61. }
    62. if(u == root && ans>=2) vis[u]=1;
    63. //如果一个点为根且子树>=2,则一定为割点,因为一棵树的根一删不那么它的子树一定不连通了
    64. }
    65. int main()
    66. {
    67. n=read(); m=read();
    68. memset(head,-1,sizeof(head));
    69. for(int i=1;i<=m;++i)
    70. {
    71. int u=read(),v=read();
    72. add(u,v);
    73. add(v,u);
    74. }
    75. for(int i=1;i<=n;++i)
    76. {
    77. if(!dfn[i]) tarjan(i,i);
    78. }
    79. for(int i=1;i<=n;++i)
    80. {
    81. if(vis[i]) res++; //如果点i是割点,计数器加1
    82. }
    83. write(res); putchar('\n');
    84. for(int i=1;i<=n;++i)
    85. {
    86. if(vis[i])
    87. {
    88. write(i);
    89. putchar(' ');
    90. }
    91. }
    92. return 0;
    93. }

    二 . 洛谷 T103481 【模板】割边

    题目描述

    给定一个 n 个点 m 条边的无向图,求割边数量。

    输入格式

    第一行两个整数,n,m。

    接下来 m 行,每行两个整数 u,v,表示一条连接 u 和 v 的有向边。

    输出格式

    共一行,输出值为割边数量。

    输入输出样例

    输入 #1

    6 7
    1 2
    2 3
    3 1
    3 4
    4 5
    5 6
    4 6

    输出 #1

    1

    说明/提示

    对于 100% 的数据,1\leqslant n \leqslant 5\times10^4,1\leqslant m\leqslant 3\times10^5


    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. int n,m;
    8. const int maxn=1e6+5;
    9. struct node{
    10. int to,next;
    11. }edge[maxn<<1];
    12. int head[maxn],num=1;
    13. int dfn[maxn],low[maxn],cnt=0,res=0;
    14. bool vis[maxn];
    15. inline int read()
    16. {
    17. int x=0,f=1;
    18. char c=getchar();
    19. while(c<'0'||c>'9')
    20. {
    21. if(c=='-') f=-1;
    22. c=getchar();
    23. }
    24. while(c>='0' && c<='9')
    25. {
    26. x=(x<<3)+(x<<1)+(c^48);
    27. c=getchar();
    28. }
    29. return x*f;
    30. }
    31. inline void write(int x)
    32. {
    33. if(x<0) putchar('-'),x=-x;
    34. if(x>9) write(x/10);
    35. putchar(x%10+'0');
    36. }
    37. inline void add(int u,int v)
    38. {
    39. edge[++num].to=v;
    40. edge[num].next=head[u];
    41. head[u]=num;
    42. }
    43. inline void tarjan(int u,int root)
    44. {
    45. dfn[u]=low[u]=++cnt;
    46. int ans=0;
    47. for(int i=head[u];i!=-1;i=edge[i].next)
    48. {
    49. int v=edge[i].to;
    50. if(!dfn[v])
    51. {
    52. tarjan(v,i);
    53. low[u]=min(low[u],low[v]);
    54. if(low[v]>dfn[u]) //第一类定义
    55. {
    56. vis[i]=vis[i^1]=1; //重边也是桥
    57. }
    58. }
    59. else if(i!=(root^1)) low[u]=min(low[u],dfn[v]);
    60. //第二类定义,也就是通过i跳不到搜索树上的边的节点
    61. }
    62. }
    63. int main()
    64. {
    65. n=read(); m=read();
    66. memset(head,-1,sizeof(head));
    67. for(int i=1;i<=m;++i)
    68. {
    69. int u=read(),v=read();
    70. add(u,v);
    71. add(v,u);
    72. }
    73. for(int i=1;i<=n;++i)
    74. {
    75. if(!dfn[i]) tarjan(i,0);
    76. }
    77. for(int i=2;i<=num;i+=2) //无向边不用重复走,直接跳2格
    78. {
    79. if(vis[i]) res++;
    80. }
    81. write(res);
    82. return 0;
    83. }

  • 相关阅读:
    Python编程语言学习笔记
    蓝牙耳机什么牌子音质最好?音质超好的蓝牙耳机推荐
    ECE368 Programming Assignment 3
    集群常用群起脚本
    案例:MySQL主从复制与读写分离
    香港Web3.0生态现状
    【广州华锐互动】人体血管器官3D动态展示为医学生提供哪些便利?
    【debian系统arm架构安装docker】且换源后依旧不行就离线导入镜像
    使用Tomcat部署SpringBoot项目
    labelimg一直闪退怎么解决啊
  • 原文地址:https://blog.csdn.net/gzkeylucky/article/details/126246658