2016-01-22 133 views
3

所以基本上我想在C++中實現這個Finding all cycles in undirected graphs(唯一的區別是圖是加權的),但那不是我真正的問題,因爲我可能處理它後來。在C++中實現在無向圖算法中尋找循環

我試圖將C#代碼重寫爲C++,但我仍然對C++中的OOP沒有信心,我不太明白自己做錯了什麼。我用調試器,我的程序甚至沒有進入findNewCycles函數,我也很確定有更多的問題,但目前我想知道如何開始。我的Path類的構造函數有問題(至少調試器提示我這樣做),但我不明白爲什麼。你能幫我麼?這是我的代碼:

#include <iostream> 
#include <utility> 
#include <vector> 
#include <algorithm> 

using namespace std; 

class Graph { 
     struct Edge { 
       int vert[2]; 
       double value; 
      public: 
       Edge(int vec1, int vec2, double w) { 
        vert[0] = vec1; 
        vert[1] = vec2; 
        value = w; 
       }; 
     }; 

     struct Path { 
       vector<int> vertices; 
       double totalValue; 
      public: 
       Path() : totalValue(0) {}; 
       Path(vector<int> v, double tv) : vertices(v), totalValue(tv) {}; 
       Path(const Path &a) { 
        totalValue = a.totalValue; 
        vertices = a.vertices; 
       } 
     }; 

     int vortexCount, edgeCount, cycleCount; 
     vector<Path> cycles; 
     vector<Edge> edges; 

     void findNewCycles(Path a) { 
      int n = a.vertices[0]; 
      int x; 
      Path sub(a); 

      for(int i = 0; i < edgeCount; i++) { 
       for(int j = 0; j <=1; j++) { 
        if (edges[i].vert[j] == n) { 
         x = edges[i].vert[(j+1)%2]; 

         if (!visited(x, a)) { 
          sub.totalValue += edges[i].value; 
          sub.vertices.insert(sub.vertices.begin(), x); 
          findNewCycles(sub); 
         } 
         else if ((a.vertices.size() > 2) && (x == a.vertices[a.vertices.size() - 1])) { 
          Path normal = normalize(a); 
          Path inv = invert(normal); 
          if(isNew(normal) && isNew(inv)) cycles.push_back(normal); 
         } 
        } 
       } 
      } 
     } 

     bool equals(Path a, Path b) { 
      if((a.vertices.size() == b.vertices.size()) && (a.totalValue == b.totalValue)) { 
       for (unsigned i=0; i < a.vertices.size(); i++) { 
        if(a.vertices[i] != b.vertices[i]) return false; 
       } 
       return true; 
      } 
      else return false; 
     } 

     Path invert(Path a) { 
      Path inverted(a); 
      reverse(inverted.vertices.begin(), inverted.vertices.end()); 
      return normalize(inverted); 
     } 

     Path normalize(Path a) { 
      Path normalized(a); 
      vector<int>::iterator smallest = min_element(normalized.vertices.begin(), normalized.vertices.end()); 
      std::rotate(normalized.vertices.begin(), smallest, normalized.vertices.end()); 
      return normalized; 
     } 

     bool isNew(Path a) { 
      for(int i=0; i<cycleCount; i++) { 
       if(equals(cycles[i], a)) { 
        return false; 
       } 
      } 
      return true; 
     } 

     bool visited(int n, Path a) { 
      for (unsigned i=0; i < a.vertices.size(); i++) { 
       if(a.vertices[i] == n) return true; 
      } 
      return false; 
     } 

    public: 
     Graph(int size) : vortexCount(size), edgeCount(0), cycleCount(0) {}; 
     ~Graph() {}; 

     vector<Edge>::iterator findEdge(int v1, int v2) { 
      if(v1 == v2 || v1 > vortexCount || v2 > vortexCount) return edges.end(); 
      vector<Edge>::iterator iter; 

      for(iter = edges.begin(); iter != edges.end(); ++iter) { 
       if(iter->vert[0] == v1 && iter->vert[1] == v2) return iter; 
       if(iter->vert[1] == v1 && iter->vert[0] == v2) return iter; 
      } 
      return edges.end(); 
     } 

     bool addEdge(int v1, int v2, double value) { 
      if(v1 == v2 || v1 > vortexCount || v2 > vortexCount) return false; 

      vector<Edge>::iterator p = findEdge(v1, v2); 

      if(p != edges.end()) { 
       p->value = value; 
      } 
      else { 
       Edge edge(v1, v2, value); 
       edges.push_back(edge); 
       edgeCount++; 
      } 
      return true; 
     } 

     void runCycleSearch() { 
      for (int i = 0; i < edgeCount; i++) { 
       for (int j = 0; j < 2; j++) { 
        cout << i << " " << j; 
        Path searchPath; 
        searchPath.vertices.push_back(edges[i].vert[j]); 
        findNewCycles(searchPath); 
       } 
      } 

      for(int i=0; i<cycleCount; i++) { 
       for(unsigned j=0; j<cycles[i].vertices.size(); j++) { 
        cout << cycles[i].vertices[j] << " "; 
       } 
       cout << cycles[i].totalValue; 
      } 
     } 

}; 

int main() { 
    int n, v1, v2; 
    double val; 
    bool control = true; 

    cin >> n; 
    Graph graph(n); 

    while(control) { 
     cin >> v1; 
     if(v1 == -1) break; 
     cin >> v2 >> val; 

     control = graph.addEdge(v1, v2, val); 
    } 

    graph.runCycleSearch(); 
} 
+0

因此,顯然我不能使用調試器(事實上,這是5:30上午在這裏沒有幫助) - 它確實進入findNewCycles函數,我不確定(但)有什麼問題沒有顯示任何週期雖然 - cycles.push_back(正常)已被執行。 – tuptus

回答

0

你確定你正在離開while循環嗎?

嘗試加入這一行,你讀過之後輸入:

cout << "v1=" << v1 << ", v2=" << v2 << " val=" << val << endl; 

,改變while (control)

for (int i=0; i < n; i++) 
+0

n是一個頂點數,所以你不能把'while(控制)'改爲'for(int i = 0; i valdem

0

我發現的第一個錯誤。當您找到一個循環時,您沒有更新cycleCount變量。即

    else if ((a.vertices.size() > 2) && (x == a.vertices[a.vertices.size() - 1])) { 
         Path normal = normalize(a); 
         Path inv = invert(normal); 
         if(isNew(normal) && isNew(inv)) cycles.push_back(normal); 
        } 

    else if ((a.vertices.size() > 2) && (x == a.vertices[a.vertices.size() - 1])) { 
         Path normal = normalize(a); 
         Path inv = invert(normal); 
         if (isNew(normal) && isNew(inv)) { 
          cycleCount++; 
          cycles.push_back(normal); 
         } 

        } 

我的建議是隻爲這個錯誤替換:刪除edgeCountcycleCount可言,您可以通過使用cycles.size()edges.size()

達到他們的計數我也改變了印刷有點點:

in void runCycleSearch() function: 

    cout << "Cycles:\n"; 
    for (int i = 0; i<cycleCount; i++) { 
     for (unsigned j = 0; j<cycles[i].vertices.size(); j++) { 
      cout << cycles[i].vertices[j] << " "; 
     } 
     cout << cycles[i].totalValue; 
     cout << "\n"; 
    } 

但是這段代碼非常粗心並且充滿了錯誤。例如案例

4 
1 2 0 
2 3 0 
3 4 0 
1 4 0 

它返回

Cycles: 
1 2 4 0 
1 3 2 0 
2 4 3 0 
1 4 3 0 

我可以繼續糾正這個代碼,但對我來說更容易從頭開始重寫:)有很多的問題:

  1. 將圖形表示爲邊的列表,因此找到特定的邊需要O(E)時間。這是非常低效的,將其替換爲鄰接列表
  2. 儘量避免複製對象,每個向量都在複製,例如isNew(Path a)您需要將其替換爲可能的引用。
  3. 在線性時間檢查路徑中存在頂點。爲此使用全局集合或無序集合。您也可以使用全局路徑變量,並且不需要在遞歸調用時複製它。