正题
题目大意
nnn个点mmm条边的联通图,去掉一个点使得其变为一棵树
求能去掉哪些点
解题思路
首先去掉后就是一棵n−1n-1n−1个节点的树,也就是有n−2n-2n−2条边,这样我们就需要去掉m−n+2m-n+2m−n+2条边,也就是去掉入度为m−n+2m-n+2m−n+2的点。
但是需要去掉后图任然是联通图,也就是去掉的是非割点,tarjantarjantarjan求割点即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node{int to,next;
}a[N*2];
int n,m,tot,cnt,in[N],ls[N],dfn[N],low[N];
bool mark[N];
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void tarjan(int x){dfn[x]=low[x]=++cnt;int flag=0;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);if(dfn[x]<=low[y]){flag++;if((x!=1||flag>1)&&!mark[x])mark[x]=1;}}else low[x]=min(low[x],dfn[y]);}
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x);in[x]++;in[y]++;}tarjan(1);int ans=0;for(int i=1;i<=n;i++)if(!mark[i]&&in[i]==m-n+2)ans++;printf("%d\n",ans);for(int i=1;i<=n;i++)if(!mark[i]&&in[i]==m-n+2)printf("%d ",i);
}