嗯》。。。前面说了Tarjan缩点
现在来tarjan割点
看洛谷试炼场提高组模板,啥都有2333
先说割点的定义
就是你把这个点和与这个点相连的边都咔嚓了之后
原来相互连接在一起的一堆点,就变成相互连接在一起的两堆点
专业点就是一个联通快变成了两个联通快
值得注意的是根节点不是割点,不然就会像我一样傻傻两天不知错在何处
嗯…同样是tarjan,
因为我们会发现在一个环内而不跟环外任意一点相连接的点不是割点
但是神奇的是在一个环内又和环外面的某点相连的点竟然是割点
嗯。。。。总之呢,涉及到了环的问题,tarjan貌似就挺好用
同样的dfn和low,不过有一些东西有所改变
首先tarjan( int pos ,int start) 对,我们要时刻记录一下最开始的那个头头start,有很多讨厌的细节跟他有关系
接下来是(!dfn[pos])的情况下,我们对low的处理方式没什么改变
不过我们应该想到这个时候可能有割点的出现
如果dfn[pos]0的时候,if( low[to] >=dfn[pos] &&pos!=start)
这个时候pos就是割点。因为后面这个if表示的意思就是,我的顺着我的儿子往下走是不会走回去的,那么我就算在某一环里面,我也是和环外的点有联系的,那么我就一定是割点。(当然,特殊情况就是posstart,因为你的start可能就是可怜的只在环里面和外界没有联系的那个23333)
但也正是我们对start出现错误的提防,我们需要考虑一下start的感受
如果start真的是割点呢?于是我们就想到,当且仅当这个start有两个或两个以上之前没有进行处理过的儿子,它才是割点。稍画一画就知道了…
所以我们遇到dfn[pos]0 的时候记tot++;最后在pos的tarjan结束的时候
if(posfa&&tot>=2) pos是割点
然后是我们对所有的儿子都有这样一个处理:
low [pos] = min( low[pos] , dfn[to] )
这个跟缩点是一样的,只不过没有是否入栈的那个限制罢了。
接下来是我写的代码(⊙o⊙)…
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#if 0
Writer: Goes && G.S.M.
Just a game
Enjoy it
#endif
inline int read(){
char ch=getchar();int sign=0,sum=0;
while((ch!='-')&&(ch<'0'||ch>'9'))
ch=getchar();
if(ch=='-') sign=1,ch=getchar();
while(ch<='9'&&ch>='0'){
sum*=10;sum+=ch-'0';ch=getchar();
}
if(sign==1) return -sum;
else return sum;
}
const int N=1000000+10;
int n,m;
struct ss{
int to,nex;
}edge[N];int head[N],ecnt;
void add(int x,int y)
{
edge[++ecnt]=(ss){y,head[x]};
edge[++ecnt]=(ss){x,head[y]};
head[x]=ecnt-1,head[y]=ecnt;
}
int dfn[N],low[N],cnt;
bool cut[N];
void tarjan(int pos,int fa){
int tot=0;
dfn[pos]=low[pos]=++cnt;
for(int i=head[pos];i;i=edge[i].nex){
int v=edge[i].to;
if(!dfn[v]){
tarjan(v,fa);
low[pos]=min(low[pos],low[v]);
if(low[v]>=dfn[pos]&&pos!=fa)
cut[pos]=true;
if(pos==fa) tot++;
}
low[pos]=min(low[pos],dfn[v]);
}
if(pos==fa&&tot>=2) cut[pos]=true;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
add(read(),read());
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i,i);
int ans=0;
for(int i=1;i<=n;i++)
if(cut[i]) ans++;
cout<<ans<<endl;
for(int i=1;i<=n;i++)
if(cut[i]) cout<<i<<" ";
return 0;
}