码迷,mamicode.com
首页 > 其他好文 > 详细

图论中环的判断

时间:2019-04-15 11:47:55      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:sem   ini   init   find   过程   为什么   取消   als   dfs   

无向图环的判断

  • 并查集判断
    • 如果两个结点父亲相同,并且两个结点之间有边相连,则存在环
def init();
def find(int x);//必须进行路径压缩
def merge(int x, int y);
if(find(x) == find(y) && G[x][y] != 0){ cycle = true;}
else merge(x,y);
  • DFS判断
    • dfs的过程中如果遇到已经访问过的点,并且这个点不是自己的直接父亲,那么就必然存在环
public class Cycle {
?????private boolean[] marked;
?????private boolean hasCycle;
?????public Cycle(Graph G) {???????
?????????this.marked = new boolean[G.V()];
?????????this.hasCycle = false;
?????????for(int i=1; i<G.V(); i++) {
??????????????if(!marked[i]) {
??????????????????//默认第一个结点没有父节点
??????????????????dfs(G, i, -1);
??????????????}
?????????}
?????}

?????private void dfs(Graph G, int cur, int pre) {
?????????marked[cur] = true;
?????????for(Integer nxt : G.adj(cur)) {
??????????????if(!marked[nxt]) {
??????????????????dfs(G, nxt, cur);
??????????????}
??????????????else if(nxt != pre) {
??????????????????this.hasCycle = true;
??????????????}
?????????}
?????}
?????public boolean hasCycle() {return this.hasCycle;}

有向图环的判断

  • 单纯判断
    • 在dfs的过程中,把dfs经过的结点全部保存在一个栈上(或者直接用布尔数组进行标记),然后每当经过一个结点时,判断当前结点是否在栈上,是则有环
    • 事实上其实质就是,在dfs的过程中又遇到了已经访问过的点,则必然存在环
  • 问题:为什么这里不需要考虑:如果该点已经被访问过并且该点是父亲结点的情况呢?无向图中不是考虑了吗?
    • 这里是有向图,如果从孩子结点能有边返回到父亲结点,那么显然这两者之间存在环。
  • 记录环中的结点
    • 需要用栈记录当前路径经过的结点,并且记录每个结点的父亲结点,也就是说记录一下在当前路径中,当前结点是哪一个结点来的。
    • 如果遇到了一个结点已经被访问过并且在栈上, 那么必然存在一个有向环。从这个结点出发,一直找当前结点的父结点,记录到结果容器里面,直到又遇到这个结点。
    • 注意这个dfs路径记录栈,当某一次dfs要返回的时候(此时已经确定在 这一遍dfs中无法找到环),则沿途回溯取消所有结点在栈上的标记(把布尔数组置为false)
public class DiCycle {
?????private boolean[] marked;//记录结点是否访问过
?????private int[] edgeTo;//记录该结点的父节点
?????private Stack<Integer> cycle;
?????private boolean[] onStack;//记录当前访问路径上的结点
????
?????public DiCycle(Digraph G) {
?????????marked = new boolean[G.V()];
?????????edgeTo? = new int[G.V()];
?????????cycle = new Stack<Integer>();
?????????onStack = new boolean[G.V()];
?????????for(int i=0; i<G.V(); i++) {
??????????????if(!marked[i]) {
??????????????????dfs(G, i);
??????????????}
?????????}
?????}
?????private void dfs(Digraph G, int v) {
?????????// TODO Auto-generated method stub
?????????marked[v] = true;
?????????onStack[v] = true;
?????????for(Integer w : G.adj(v)) {
??????????????if(this.hasCycle()) return ;
??????????????else if(!marked[w]) {
??????????????????edgeTo[w] = v;
??????????????????dfs(G , w);
??????????????}
??????????????else if(onStack[w]) {
??????????????????for(int x=v; x!=w; x=edgeTo[x]) {
???????????????????????cycle.push(x);
??????????????????}
??????????????????cycle.push(w); 
??????????????????cycle.push(v);
??????????????}
?????????}
?????????onStack[v] = false;//回溯时取消其在栈上,相当于清空栈,便于下一次dfs???????
?????}

?????public void showCycle() {
?????????if(!this.hasCycle()) System.out.println("no cycle...");
?????????Stack<Integer> s = new Stack<Integer>();
?????????s = (Stack<Integer>) cycle.clone();
?????????while(!s.isEmpty()) {
??????????????System.out.println(s.peek());
??????????????s.pop();
          }
?????}

图论中环的判断

标签:sem   ini   init   find   过程   为什么   取消   als   dfs   

原文地址:https://www.cnblogs.com/czsharecode/p/10709715.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!