随笔 - 58,  文章 - 0,  评论 - 4,  阅读 - 3296

一、题目描述:

  给你一个 n 个点,m 条边的无向图。

  求出所有割点,按节点编号升序排序。

  数据范围:1n2×104,1m1×105


 二、解题思路:

  割点板子题,不需要思路。时间复杂度 O(n+m)


 三、完整代码:

复制代码
 1 #include<iostream>
 2 #define N 20010
 3 #define M 100010
 4 using namespace std;
 5 int n,m,rt,cc,tot,num;
 6 int ans[N],dfn[N],low[N];
 7 struct EDGE{
 8     int v,nxt;
 9 }edge[M*2];
10 int head[N],cnt;
11 void add(int u,int v)
12 {
13     edge[++cnt].v=v;
14     edge[cnt].nxt=head[u];
15     head[u]=cnt;
16 }
17 void tarjan(int u)
18 {
19     dfn[u]=low[u]=++tot;int son=0;
20     for(int i=head[u];i!=-1;i=edge[i].nxt)
21     {
22         int to=edge[i].v;
23         if(!dfn[to]){
24             //就是说,这是一颗以u为根的子树了
25             //且它至少与当前访问过的其他子树独立 
26             son++;tarjan(to);
27             low[u]=min(low[u],low[to]); 
28             //反正是我的子树了
29             //low[u]代表这颗子树能到达的最小dfn吧 
30             if(low[to]>=dfn[u]&&u!=rt)
31                 num+=ans[u]==0,ans[u]=1;
32             //如果说当前子树被隔断,自然u就是割点 
33         }else    low[u]=min(low[u],dfn[to]);
34     }
35     if(son>=2&&u==rt) num+=ans[u]==0,ans[u]=1;
36     //特殊判断根节点,很容易理解 
37 }
38 int main()
39 {
40     ios::sync_with_stdio(false);
41     cin.tie(0);cout.tie(0);
42     cin>>n>>m;
43     for(int i=1;i<=n;i++)
44         head[i]=-1;
45     for(int i=1,u,v;i<=m;i++)
46         cin>>u>>v,add(u,v),add(v,u);
47     for(int i=1;i<=n;i++)
48         if(!dfn[i]) rt=i,tarjan(i);
49     //tarjan,一个还不错的算法 
50     cout<<num<<'\n';
51     for(int i=1;i<=n;i++)
52         if(ans[i])    cout<<i<<" ";
53     return 0;
54 }
复制代码

四、写题心得:

  今天本来学的是圆方树,结果我连点双是什么我都不知道,先来学了割点。收获经验如下:

  1=>Exp++

  2=>Exp++

posted on   trh0630  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示