题目背景
割点
题目描述
给出一个nn个点,mm条边的无向图,求图的割点。
输入输出格式
输入格式:
第一行输入n,mn,m
下面mm行每行输入x,yx,y表示xx到yy有一条边
输出格式:
第一行输出割点个数
第二行按照节点编号从小到大输出节点,用空格隔开
输入输出样例
输入样例#1: 复制
6 7 1 2 1 3 1 4 2 5 3 5 4 5 5 6
输出样例#1: 复制
1 5
说明
对于全部数据,n \le 20000n≤20000,m \le 100000m≤100000
点的编号均大于00小于等于nn。
tarjan图不一定联通。
#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
int ret=0; char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret;
}
const int N=2e5+5;
int n,m,ans[N],num;
int cnt,he[N],to[N],nxt[N];
int sgn,low[N],dfn[N];
inline void add(int u,int v)
{
to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt;
}
void tar(int u,int r)
{
low[u]=dfn[u]=++sgn;
int ch=0;
for(int e=he[u];e;e=nxt[e])
{
int v=to[e];
if(!dfn[v])
{
tar(v,r),low[u]=min(low[v],low[u]);
if(low[v]>=dfn[u]&&u!=r) ans[u]=1;
if(u==r) ch++;
}
low[u]=min(low[u],dfn[v]);
}
if(ch>=2&&u==r) ans[u]=1;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) tar(i,i);
for(int i=1;i<=n;i++)
if(ans[i]) num++;
printf("%d\n",num);
for(int i=1;i<=n;i++)
if(ans[i]) printf("%d ",i);
return 0;
}