求无向简单图的割点与割线的问题(邻接矩阵)

  文章参考博文:http://www.cnblogs.com/en-heng/p/4002658.html。对无相连通图的割点问题做了较为详细的描述。现将问题在这里做一个简要的描述:

  在无向连通图中,删除一个顶点v及其相连的边后,原图从一个连通分量变成了两个或多个连通分量,则称顶点v为割点,同时也称关节点。对求割点的问题,最著名的求解方法是基于DFS的。DFS过程会产生DFS搜索树。

  观察DFS搜索树,我们可以发现有两类节点可以成为割点:

  1. 对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
  2. 对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边,说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。


  我们用 dfsnum[u]记录节点u在DFS过程中被遍历到的次序号, low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)

  参考的博文中存在一个问题,度为1的结点求得的low值并是其DFS树结点的dfsnum值,即没有跳过父边,不符合“非父子边”的概念,这会在之后的求割线的问题是制造麻烦,因此,需要加上对是否为DFS树的父子边加以判断:

  过程需要一些全局变量:

        int [] dfsnum = new int[20];             //DFS结点遍历的顺序,根结点为1,接下来遍历到的依次+1
	int num = 0;                             //用来为DFS标序号,初始化为0
	int parent = 0;                          //用来判断是否根结点是割点
	static int [] parents = new int[20];     //用来记录DFS祖先的数组
	int []low = new int [20];                //每个结点在不经过DFS树的父结点时,能够回到的最小标号的结点
  寻找割点的程序如下:

	public void CutVertices(int u){                 //寻找割点/关节点
		low[u]= dfsnum[u] = ++num;
		for(int v=0;v<VertexCount;v++){             //VertexCount为实际的图中的结点个数
			if(adjMatrix[u][v]==1 && dfsnum[v]==0){   //u到v有边,且v没有访问过,adjMatrix为邻接矩阵
				parents[v] = u;
				if(u==0)
					parent++;
				CutVertices(v); //递归处理
				if(low[v]>=dfsnum[u] && u!=0)          //注意,此处为>=,u=0说明是根结点,判断方法是不一样的
					System.out.println("Cut Vertex:"+u);
				low[u] = Math.min(low[u],low[v]);
			}
			else if(adjMatrix[u][v]==1 && parents[u]!=v){              //有边,且v已经访问过,且u在DFS树中的祖先不是v
				low[u] = Math.min(low[u],dfsnum[v]);
			}
		}
		if(parent>1)
			System.out.println("Cut Vertex:0");
	}
  寻找割线的问题与割点问题类似,只是条件由
low[v]>=dfsnum[u]
  改变为:
low[v]>dfsnum[u]
  其程序如下:
        public void Bridges(int u){                 //寻找割桥/割边		
		low[u]= dfsnum[u] = ++num;
		for(int v=0;v<VertexCount;v++){         //VertexCount为实际的图中的结点个数
			if(adjMatrix[u][v]==1 && dfsnum[v]==0){   //u到v有边,且v没有访问过,adjMatrix为邻接矩阵
				parents[v] = u;
				if(u==0)
					parent++;
				Bridges(v);
				if(low[v]>dfsnum[u] && u!=0)
					System.out.println("Cut Bridge:"+u+" "+v);
				low[u] = Math.min(low[u],low[v]);
			}
			else if(adjMatrix[u][v]==1 && parents[u]!=v){              //有边,且v已经访问过,且u在DFS树中的祖先不是v
				low[u] = Math.min(low[u],dfsnum[v]);
			}
		}
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值