2009-12-03 24 views
4

我回過一個類似的問題。我目前正在研究一個Java程序,它將檢查一個圖是否可着色,即它是否不包含奇數週期(奇數長度的週期)。整個算法應該在O(V + E)時間內運行(V代表所有頂點,E代表圖中的所有邊)。我當前的算法執行深度優先搜索,記錄所有路徑中的所有頂點,然後查找後沿,然後記錄邊之間的頂點。接下來,它追蹤從後邊的一端開始的路徑,直到它碰到邊的另一端的另一個頂點,從而回退後邊完成的循環。檢查無向圖中的奇數週期

我的印象是,這種遍歷可以在O(V + E)時間內對我圖中存在的所有循環完成,但我必須缺少一些東西,因爲我的算法運行時間很長時間很長的圖(10k節點,不知道有多少邊)。

我的算法是完全錯誤的嗎?如果是這樣,任何人都可以指出我正確的方向來更好地記錄這些週期,或者可能知道它們是否有奇數個頂點?感謝您提供的任何和所有幫助。如果您需要,代碼如下。

加法:對不起,我忘記了,如果圖不是2色的,我需要提供一個奇怪的循環,證明它不是。

package algorithms311; 

import java.util.*; 
import java.io.*; 

public class CS311 { 

public static LinkedList[] DFSIter(Vertex[] v) { 
    LinkedList[] VOandBE = new LinkedList[2]; 
    VOandBE[0] = new LinkedList(); 
    VOandBE[1] = new LinkedList(); 

    Stack stack = new Stack(); 

    stack.push(v[0]); 
    v[0].setColor("gray"); 

    while(!stack.empty()) { 
     Vertex u = (Vertex) stack.peek(); 
     LinkedList adjList = u.getAdjList(); 
     VOandBE[0].add(u.getId()); 

     boolean allVisited = true; 
     for(int i = 0; i < adjList.size(); i++) { 
      if(v[(Integer)adjList.get(i)].getColor().equals("white")) { 
       allVisited = false; 
       break; 
      } 
      else if(v[(Integer)adjList.get(i)].getColor().equals("gray") && u.getPrev() != (Integer)adjList.get(i)) { 
       int[] edge = new int[2]; //pair of vertices 
       edge[0] = u.getId(); //from u 
       edge[1] = (Integer)adjList.get(i); //to v 
       VOandBE[1].add(edge); 
      } 
     } 
     if(allVisited) { 
      u.setColor("black"); 
      stack.pop(); 
     } 
     else { 
      for(int i = 0; i < adjList.size(); i++) { 
       if(v[(Integer)adjList.get(i)].getColor().equals("white")) { 
        stack.push(v[(Integer)adjList.get(i)]); 
        v[(Integer)adjList.get(i)].setColor("gray"); 
        v[(Integer)adjList.get(i)].setPrev(u.getId()); 
        break; 
       } 
      } 
     } 
    } 
    return VOandBE; 
} 

public static void checkForTwoColor(String g) { //input is a graph formatted as assigned 

    String graph = g; 

    try { 

     // --Read First Line of Input File 
     // --Find Number of Vertices 

     FileReader file1 = new FileReader("W:\\Documents\\NetBeansProjects\\algorithms311\\src\\algorithms311\\" + graph); 
     BufferedReader bReaderNumEdges = new BufferedReader(file1); 

     String numVertS = bReaderNumEdges.readLine(); 
     int numVert = Integer.parseInt(numVertS); 

     System.out.println(numVert + " vertices"); 





     // --Make Vertices 

     Vertex vertex[] = new Vertex[numVert]; 

     for(int k = 0; k <= numVert - 1; k++) { 
      vertex[k] = new Vertex(k); 
     } 

     // --Adj Lists 


     FileReader file2 = new FileReader("W:\\Documents\\NetBeansProjects\\algorithms311\\src\\algorithms311\\" + graph); 
     BufferedReader bReaderEdges = new BufferedReader(file2); 
     bReaderEdges.readLine(); //skip first line, that's how many vertices there are 

     String edge; 

     while((edge = bReaderEdges.readLine()) != null) { 

      StringTokenizer ST = new StringTokenizer(edge); 

      int vArr[] = new int[2]; 
      for(int j = 0; ST.hasMoreTokens(); j++) { 
       vArr[j] = Integer.parseInt(ST.nextToken()); 
      } 


      vertex[vArr[0]-1].addAdj(vArr[1]-1); 
      vertex[vArr[1]-1].addAdj(vArr[0]-1); 

     } 

     LinkedList[] l = new LinkedList[2]; 

     l = DFSIter(vertex);//DFS(vertex); 

     System.out.println(l[0]); 



     for(int i = 0; i < l[1].size(); i++) { 
      int[] j = (int[])l[1].get(i); 
      System.out.print(" [" + j[0] + ", " + j[1] + "] "); 
     } 



     LinkedList oddCycle = new LinkedList(); 
     boolean is2Colorable = true; 


     //System.out.println("iterate through list of back edges"); 

     for(int i = 0; i < l[1].size(); i++) { //iterate through the list of back edges 
      //System.out.println(i); 
      int[] q = (int[])(l[1].get(i)); // q = pair of vertices that make up a back edge 
      int u = q[0]; // edge (u,v) 
      int v = q[1]; 

      LinkedList cycle = new LinkedList(); 

      if(l[0].indexOf(u) < l[0].indexOf(v)) { //check if u is before v 
       for(int z = l[0].indexOf(u); z <= l[0].indexOf(v); z++) { //if it is, look for u first; from u to v 
        cycle.add(l[0].get(z)); 
       } 
      } 
      else if(l[0].indexOf(v) < l[0].indexOf(u)) { 
       for(int z = l[0].indexOf(v); z <= l[0].indexOf(u); z++) { //if it is, look for u first; from u to v 
        cycle.add(l[0].get(z)); 
       } 
      } 



      if((cycle.size() & 1) != 0) { //if it has an odd cycle, print out the cyclic nodes or write them to a file 

       is2Colorable = false; 

       oddCycle = cycle; 

       break; 
      } 
     } 
     if(!is2Colorable) { 
      System.out.println("Graph is not 2-colorable, odd cycle exists"); 
      if(oddCycle.size() <= 50) { 
       System.out.println(oddCycle); 
      } 
      else { 
       try { 
        BufferedWriter outFile = new BufferedWriter(new FileWriter("W:\\Documents\\NetBeansProjects\\algorithms311\\src\\algorithms311\\" + graph + "OddCycle.txt")); 
        String cyc = oddCycle.toString(); 
        outFile.write(cyc); 
        outFile.close(); 
       } 
       catch (IOException e) { 
        System.out.println("Could not write file"); 
       } 
      } 
     } 
    } 
    catch (IOException e) { 
     System.out.println("Could not open file"); 
    } 
    System.out.println("Done!"); 
} 

public static void main(String[] args) { 
     //checkForTwoColor("smallgraph1"); 
     //checkForTwoColor("smallgraph2"); 
     //checkForTwoColor("smallgraph3"); 
     //checkForTwoColor("smallgraph4"); 
     checkForTwoColor("smallgraph5"); 

     //checkForTwoColor("largegraph1"); 
    } 
} 

頂點類

package algorithms311; 

import java.util.*; 

public class Vertex implements Comparable { 

    public int id; 
    public LinkedList adjVert = new LinkedList(); 
    public String color = "white"; 
    public int dTime; 
    public int fTime; 
    public int prev; 
    public boolean visited = false; 

    public Vertex(int idnum) { 
     id = idnum; 
    } 

    public int getId() { 
     return id; 
    } 

    public int compareTo(Object obj) { 
     Vertex vert = (Vertex) obj; 
     return id-vert.getId(); 
    } 

    @Override public String toString(){ 
     return "Vertex # " + id; 
    } 

    public void setColor(String newColor) { 
     color = newColor; 
    } 

    public String getColor() { 
     return color; 
    } 

    public void setDTime(int d) { 
     dTime = d; 
    } 

    public void setFTime(int f) { 
     fTime = f; 
    } 

    public int getDTime() { 
     return dTime; 
    } 

    public int getFTime() { 
     return fTime; 
    } 

    public void setPrev(int v) { 
     prev = v; 
    } 

    public int getPrev() { 
     return prev; 
    } 

    public LinkedList getAdjList() { 
     return adjVert; 
    } 

    public void addAdj(int a) { //adds a vertex id to this vertex's adj list 
     adjVert.add(a); 
    } 

    public void visited() { 
     visited = true; 
    } 

    public boolean wasVisited() { 
     return visited; 
    } 
} 

回答

4

我的印象是,這種穿越的可能在O完成(V + E)的時間存在於我的圖表中的所有周期下

在圖中可能有比O(V + E)多得多的週期。如果你迭代所有這些,你會跑很長時間。回到最初的想法,你可以嘗試實現一種簡單的算法,以兩種顏色對圖進行着色(將任意節點標記爲黑色,將所有鄰居標記爲黑色,將所有鄰居標記爲黑色,等等;這將是廣度優先搜索)。這確實是在O(V + E)時間完成的。如果你成功了,那麼圖形是可着色的。如果你失敗了,事實並非如此。

編輯:如果你需要證明圖不是2着色一個週期,只是記錄了每一個節點你穿越到它的頂點。當你碰巧從黑色頂點A以黑色頂點B遍歷(因此需要以色黑B爲白色,證明你的圖形是不2-着色),您可以通過回想父母那裏得到的循環:

X -> Y -> Z -> U -> V -> P -> Q -> A 
        \-> D -> E -> B 

然後,A-B-E-D-V-P-Q(到他們共同的祖先的路徑)是你需要的循環。

請注意,在此版本中,您不必檢查所有週期,您只需輸出第一個週期,其中樹中的後端都具有以相同顏色着色的頂點。

+0

增加了一個編輯...如果圖不是2-colorable,我需要提供一個奇怪的週期,證明它​​不是2-colorable .. – devers 2009-12-03 10:15:11

+0

我編輯我的答案以及。 – 2009-12-03 10:19:22

2

您正在描述一個二部圖。二部圖是可着色的,它不包含奇數長度的週期。您可以使用BFS來證明圖形是雙向的。希望這可以幫助。