割点(模板)
题目描述
给出一个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;
}

浙公网安备 33010602011771号