void tarjan(int u,int root,int fa)
{
DFN[u]=low[u]=++index;
instack[u]=1;
int cnt=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!instack[v])
{
tarjan(v,root,u);
cnt++;
if(low[u]>low[v])//如果当前结点的low值大于子节点的low值,说明子节点连到到比当前结点更早的节点,则更新当前结点的low值跟子节点一样。
low[u]=low[v];
if(u==root && cnt>1)//如果u等于根结点并且有2个子树,则为割点。这句也也可以放在循环外,由于可能会进入多次,所以最后如果是割点的话增加的连通分量可能不止1个。即根节点有多个子树。
{
cut_point[u]=1;
add_block[u]++;
}
else if(u!=root && low[v]>=DFN[u])//如果u不等于根节点并且子节点可以回到的最早的点在该点之后
{
cut_point[u]=1;
add_block[u]++;
}
}
else if(v!=fa && low[u] > DFN[v])//如果有边回到了之前的点,则更新该起始点的low值
low[u]=DFN[v];
}
}
边(u,v)是无向图的桥当且仅当(u,v)满足 low[v]>DFN[u],也就是边(u,v)是v到达其祖先的必经之路,所以去掉边(u,v),连通分支数就会增加,但是如果u,v之间存在重边的话,就不是桥了,所以我们要对重边判定
void Tarjan(int u,int pre)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
int son = 0;
for(int i = head[u];i != -1;i = edge[i].next)
{
v = edge[i].to;
if(v == pre)continue;
if( !DFN[v] )
{
son++;
Tarjan(v,u);
if(Low[u] > Low[v])Low[u] = Low[v];
//桥
//一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u) DFN[u])
{
bridge++;
edge[i].cut = true;
edge[i^1].cut = true;
}
//割点
//一个顶点u是割点,当且仅当满足(1)或(2) (1) u为树根,且u有多于一个子树。
//(2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,
//即u为v在搜索树中的父亲),使得DFS(u)<=Low(v)
if(u != pre && Low[v] >= DFN[u])//不是树根
{
cut[u] = true;
add_block[u]++;
}
}
else if( Low[u] > DFN[v])
Low[u] = DFN[v];
}
//树根,分支数大于1
if(u == pre && son > 1)cut[u] = true;
if(u == pre)add_block[u] = son - 1;
Instack[u] = false;
top--;
}
#include
#include
#include
#include
#include
const int maxn=10005;
int DFN[maxn];//记录每个点被访问到的时间
int low[maxn];//记录点可以直接或间接到达的最早被访问到的点(也就是那个强连通分量的根)
int stack[maxn];
int sccnum[maxn];//标记每个点属于第几个强连通分量
bool instack[maxn];
int sccNum;//强连通分量的数目
int top;
int index;
int n;
struct node
{
int to;
int next;
}edge[10*maxn];
int head[maxn];
int tot;
void addedge(int from,int to)
{
edge[tot].to=to;
edge[tot].next=head[from];
head[from]=tot++;
}
void tarjan(int u)
{
DFN[u]=low[u]=++index;//刚刚搜到这个点,DFN和low都赋值为被访问到的时间
stack[top++]=u;//入栈
instack[u]=1;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].to;
if(!DFN[v])//如果没有被访问过
{
tarjan(v);
if(low[u]>low[v]) low[u]=low[v]; //这个时候low可能要修改,值为i或者i的子树可以到达的最早被访问到的点的时间
}
else if(instack[v])//已经在栈
{
if(low[u]>DFN[v]) low[u]=DFN[v];
}
}
if(DFN[u]==low[u])//找到根
{
sccNum++;
do
{
int v=stack[--top];
sccnum[v]=sccNum;
instack[v]=0;//标记出栈
}while(v!=u);
}
}
void solve()
{
memset(DFN,0,sizeof(DFN));
memset(instack,0,sizeof(instack));
index=0;
sccNum=0;
top=0;
for(int i=1;i<=n;i++)
if(!DFN[i])
tarjan(i);
}
int main()
{
int m,a,b;
while(~scanf("%d%d",&n,&m))
{
if(n==0 && m==0)
break;
memset(head,-1,sizeof(head));
tot=0;
for(int i=0;i