您的位置:首页 > 其它

点双连通分量的求解

2015-06-04 14:02 204 查看
//点双连通分量的求解
//就是通过tarjan算法求出关节点时,与关节点的子树就是一个连通分量,可以通过画图得到
//所以可以将与顶点u有关的边放到栈中,然后一但满足low[v]>=dfn[u](表面点u是割点)(注释:由于dfs,已经建好了u
//的子树,所以栈中有顶点u的子树),就可以进行退栈,直到遇到与u相关的边(由于dfs原因,之前的边都已经存入栈中
//所以第一个(u,v)边是最后一个退栈的,所以到其为止即可。)由于让访问过的边map[u][v]=map[v][u]=2,所以之前访问
//过的边不会再被访问。在dfs生成树图中能够很明显看出,就是关节点未被访问过的子树。

#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
int min(int x,int y)
{
return x<y?x:y;
}

int map[100][100],vis[100],dfn[100],depth,low[100],n,m;
void init()
{
int i,j;
memset(vis,0,sizeof(vis));
vis[1]=1;
low[1]=dfn[1]=1;
depth=1;
}
struct edge
{
int x;
int y;
};
stack<edge>s;
void dfs(int u)
{
int i,j;
for(i=1;i<=n;i++)
{
if(map[u][i]==1)
{
map[u][i]=map[i][u]=2;//标记为2使该边使用后不再被使用
edge t={u,i};
s.push(t);
if(!vis[i])
{
vis[i]=1;
depth++;
dfn[i]=low[i]=depth;
dfs(i);
low[u]=min(low[u],low[i]);
if(low[i]>=dfn[u])
{
while(1)//不断退栈,直到遇到边(u,v)
{
edge temp;
temp=s.top();
s.pop();
printf("%d-%d ",temp.x,temp.y);
if((temp.x==u&&temp.y==i)||(temp.x==i&&temp.y==u))
{
break;
}
}
printf("\n");
}
}
else low[u]=min(low[u],dfn[i]);
}
}
}
int main()
{
int i,j,v,u;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(map,0,sizeof(map));
for(i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=1;
}
init();
dfs(1);
}
}
/*
7 9
1 2
1 3
1 6
1 7
2 3
2 4
2 5
4 5
6 7
*/


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: