割點(模板)
阿新 • • 發佈:2021-10-27
題目描述
給出一個n個點,m條邊的無向圖,求圖的割點。
輸入格式
第一行輸入兩個正整數 n,m。
下面m行每行輸入兩個正整數x,y表示x到y有一條邊。
輸出格式
第一行輸出割點個數。
第二行按照節點編號從小到大輸出節點,用空格隔開。
題解
板子題,去掉該點後圖不再連通即為割點。
tarjan演算法。
#include<cstdio> #include<cstring> #include<map> #include<queue> #include<algorithm> #include<cmath> #include<iostream> using namespace std; const int MAXN=100005,MAXM=200005; //鄰接表存圖 struct edge{ int u,v; }e[MAXM]; int cnt,head[MAXM]; void add(int a,int b){ e[++cnt].u=b; e[cnt].v=head[a]; head[a]=cnt; } //tarjan int n,m,dfn[MAXN],low[MAXN],id; bool vis[MAXM]; void tarjan(int x,int fa){ dfn[x]=low[x]=++id; int child=0;//統計子樹 for(int j=head[x];j!=0;j=e[j].v){ int nx=e[j].u;//查詢連線的其他點 if(!dfn[nx]){ tarjan(nx,fa); low[x]=min(low[x],low[nx]); if(low[nx]>=dfn[x]&&x!=fa) vis[x]=1; //後面的點無法回到x之前的點,說明是割點 if(x==fa) child++; } low[x]=min(low[x],dfn[nx]); } if(child>=2&&x==fa) vis[x]=1;//標記割點 } int main(){ ios::sync_with_stdio(0); cin.tie(NULL);cout.tie(NULL); memset(head,0,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); cin>>n>>m; for(int i=1;i<=m;i++){ int a,b; cin>>a>>b; add(a,b);add(b,a); } int ans=0; for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,i); //for(int i=1;i<=n;i++) cout<<i<<" "<<dfn[i]<<" "<<low[i]<<endl; for(int i=1;i<=n;i++) if(vis[i]==1) ans++; cout<<ans<<endl; //從小到大輸出節點 for(int i=1;i<=n;i++) if(vis[i]==1) cout<<i<<" "; return 0; }