• 环的寻找:寻找无向图中所有存在的环-删除点法


            此文讨论一个无向图中存在环的问题,在不管多复杂的连通图中寻找出所有的环,使用删除点的方法。

            此外,这个版本的查找方法可以用于其他场景:找出无向图中所有的环的算法             

            结果能找到最小的环,或许要靠运气,输出该输出的环抓狂...............,这是原始算法。


    改进:

    可以输出最大环(通过跳过多度点),可以输出最小子环(通过使用最短路径)......................

            使用一个图:

           

            比如在上图中,存在多个环(1,2,3,4,5,6)(6,7,8,9)(1,2,5,6)(1,2,3,5,6).........

            怎么寻找呢?


    一、使用删除边法

            本例中,从顶点9开始,构建DFS

            1.首先删除所有度数为1的点,这样点14就被删除。这样只剩下多度顶点的环

              


            2. 若从顶点9开始,找到了环(9,8,6,7),对于顶点8和顶点7,其所有链接的边都在当前环上,则可以删除掉两个顶点;

             而9除了处于环中的边,还有其他边,则不能删除。此外,顶点6也不能删除。

             判断条件: 若顶点X链接的边在这一个环上,则可以删除此顶点。

                 

                     例如:在图中,删除的点为7和8,同时所有的链接边也删除。输出环(9.8.7.6)。


            3. 使用堆栈,再次查找10,可以输出环(10,11,12,13),同时可以删除顶点(11,12,13)。此时顶点10 的度置位1,标识为已遍历状态。

                    

            4.每次查找环,都删除度为1的节点和连接边。此时可以删除10,9,树退化为一颗子树。

                     


        5.到了一个查找重复环的时候   

             5.1. 此时没有单度节点,

             5.2. 出现问题,得重新考虑了!!!

            从顶点6开始找到所有的环:注意此过程依然为生成树的过程,每一个边都被设定为有向边。

           

       Code :

       

    	// 寻找联通集合的闭包,判断是否连通,返回闭包
    	public static void findSub(Boolean adjM[][], Set<Integer> votex, ArrayList<Set<Integer>> loopSets) {
    		if (votex.size() < 2) {// 治标不治本
    			return;
    		}
    
    		for (int m = 0; m < adjM.length;++m){
    			adjM[m][m] =false;
    		}
    		
    		// 计算顶点的度
    		Integer[] degrees = new Integer[adjM.length];
    		degrees = calVotexDegree(adjM);
    
    		//循环查找,找到所有的度不为1的闭包
    		boolean isdeleted = true;
    		while( isdeleted ){
    			isdeleted = false;
    			degrees = calVotexDegree(adjM);
    			delete1Degree(adjM, degrees);// 删除度数为1 的边
    
                             int l1 = votex.size();
    			// 更新联通集合
    			for (int i = 0; i < degrees.length; ++i) {
    				if (degrees[i] == 0) {
    					votex.remove(i);
    					for (int m = 0; m < adjM.length;++m){
    						adjM[i][m] = false;//更新度,若被移除则相关的邻接都置为false
    						adjM[m][i] = false;
    					}
    				}
    			}
    			int l2 = votex.size();
    			if(l1!=l2) isdeleted = true;
    		}
    		
    		// 遍历所有节点,逐个取出,去除非环节点
    		Set<Integer> loop = new HashSet<Integer>();
    		Set<Integer> sub = new HashSet<Integer>();
    		boolean isBlankX = false;
    		boolean isFind = false;
    
    		for (int ob : votex) {
    			int obj = ob;
    			sub.add(obj);
    			int idx = obj;
    			for (int j = idx; j < adjM[idx].length;) {
    				if (adjM[idx][j]) {
    					if (sub.contains(j) && idx != j) {
    						transSet(sub, loop);// 若已存在元素,则存在环,复制出环
    						loopSets.add(loop);
    						votex.removeAll(loop);
    						sub.clear();
    						findSub(adjM, votex, loopSets);
    						isFind = true;
    						if (votex.size() < 3) {// 剩余两个就不再寻找
    							isBlankX = true;
    						}
    						++j;
    					} else {
    						sub.add(j);
    						++j;
    					}
    				} else
    					++j;
    			}
    			if (isFind)
    				break;
    		}
    		return;
    	}

    // 输出顶点的度
    	public static Integer[] calVotexDegree(Boolean adjM[][]) {
    		Integer[] degrees = new Integer[adjM.length];
    		for (int i = 0; i < adjM.length; ++i) {
    			degrees[i] = 0;
    			for (int j = 0; j < adjM[i].length; ++j) {
    				if (adjM[i][j] == true) {
    					degrees[i] = degrees[i] + 1;
    				}
    			}
    		}
    		return degrees;
    	}

    // 更新矩阵:删除权值为1和0的边
    	public static void delete1Degree(Boolean[][] adjM, Integer[] degrees) {
    		for (int j = 0; j < adjM.length; ++j) {
    			adjM[j][j] = false;// 自身边消除掉
    			if (degrees[j] < 2) {
    				for (int k = 0; k < adjM[j].length; ++k) {
    					adjM[j][k] = false;
    					adjM[k][j] = false;
    				}
    				degrees[j] = 0;
    			}
    		}
    	}

    输出结果:输出结果具有一定的概率性,和顶点的排序有关。



  • 相关阅读:
    HDU 1527 取石子游戏 (威佐夫博奕)
    HDU 1159 Common Subsequence (LCS)
    HDU 1160 FatMouse's Speed (LIS)
    HDU 2577 How to Type (DP)
    csu 1395: Timebomb (模拟)
    csu 1556: Jerry's trouble(大数取模)
    csu 1553: Good subsequence (最长连续子序列)
    csu 1548: Design road (三分)
    csu 1547: Rectangle (01背包)
    csu 1541: There is No Alternative(Kruskal 最小生成树)
  • 原文地址:https://www.cnblogs.com/wishchin/p/9199899.html
Copyright © 2020-2023  润新知