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
 说明
n,m均为100000
tarjan 图不一定联通!!!
WA了很多次
 果然还是年轻
include
include
include
define N 100005
using namespace std;
int a,b;
 int n,m;
 int son;
 int ans;
 int root;
 int col[N];
 int dfn[N];
 int low[N];
 int col_num;
 bool is_cut[N];
struct Edge{
 int v,nxt;
 }e[N<<2];
 int head[N],tot;
void read(int &s){
 char ch=getchar();
 for(;!isdigit(ch);ch=getchar());
 for(s=0;isdigit(ch);s=s*10+ch-'0',ch=getchar());
 }
void add(int a,int b){
 e[++tot].v=b;
 e[tot].nxt=head[a];
 head[a]=tot;
 }
int tim_dfn;
void Tarjan(int x){
 low[x]=dfn[x]=++tim_dfn;
 for(int i=head[x];i;i=e[i].nxt){
 int to=e[i].v;
 if(!dfn[to]){
 Tarjan(to);
 if(x==root)son++;
 else {
 low[x]=min(low[x],low[to]);
 if(low[to]>=dfn[x])is_cut[x]=true;
 }
 }
 else
 low[x]=min(low[x],dfn[to]);
 }
 }
int main(){
 while(~scanf("%d%d",&n,&m)){
 memset(is_cut,false,sizeof(is_cut));
 memset(head,false,sizeof(head));
 memset(dfn,false,sizeof(dfn));
 memset(low,false,sizeof(low));
 tim_dfn=tot=0;
 for(int i=1;i<=m;++i){
 read(a),read(b);
 add(a,b);add(b,a);
 }
 ans=0;
 for(int i=1;i<=n;++i)
 if(!dfn[i]){
 root=i,son=0;
 Tarjan(i);
 }
 if(son>1)is_cut[root]=1;
 for(int i=1;i<=n;++i)
 if(is_cut[i])
 ans++;
 cout<<ans<<endl;
 for(int i=1;i<=n;++i)
 if(is_cut[i])
 cout<<i<<' ';
 }
 return 0;
 }