private void Dfs(Graph g, int u, int v) { _marked[v] = true; foreach (int w in g.Adj(v)) { // short circuit if cycle already found if (_cycle != null) return; if (!_marked[w]) { _edgeTo[w] = v; Dfs(g, v, w); } // check for cycle (but disregard reverse of edge leading to v) else if (w != u) { _cycle = new Collections.Stack<Integer>(); for (var x = v; x != w; x = _edgeTo[x]) { _cycle.Push(x); } _cycle.Push(w); _cycle.Push(v); } } }
private readonly int _s; // source vertex #endregion Fields #region Constructors /// <summary> /// Computes a path between <tt>s</tt> and every other vertex in graph <tt>G</tt>. /// </summary> /// <param name="g">g the graph</param> /// <param name="s">s the source vertex</param> public DepthFirstPaths(Graph g, int s) { _s = s; _edgeTo = new int[g.V]; _marked = new bool[g.V]; Dfs(g, s); }
private readonly bool[] _marked; // marked[v] = is there an s-v path #endregion Fields #region Constructors /// <summary> /// Computes the shortest path between the source vertex <tt>s</tt> /// and every other vertex in the graph <tt>G</tt>. /// </summary> /// <param name="g">g the graph</param> /// <param name="s">s the source vertex</param> public BreadthFirstPaths(Graph g, int s) { _marked = new bool[g.V]; _distTo = new int[g.V]; _edgeTo = new int[g.V]; Bfs(g, s); //assert check(G, s); }
/// <summary> /// Computes the shortest path between any one of the source vertices in <tt>sources</tt> /// and every other vertex in graph <tt>G</tt>. /// </summary> /// <param name="g">g the graph</param> /// <param name="sources">sources the source vertices</param> public BreadthFirstPaths(Graph g, IEnumerable<Integer> sources) { _marked = new bool[g.V]; _distTo = new int[g.V]; _edgeTo = new int[g.V]; for (var v = 0; v < g.V; v++) _distTo[v] = INFINITY; Bfs(g, sources); }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyG.txt"); // Prompt Console.WriteLine("2 - mediumG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); var fieName = string.Empty; switch (fileNumber) { case "1": fieName = "tinyG.txt"; break; case "2": fieName = "mediumG.txt"; break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fieName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<EdgeU>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var edge = new EdgeU(ve, we); edges.Add(edge); } lineIterator++; } var graph = new Graph(v, e, edges); Console.WriteLine(graph); Console.ReadLine(); }
/// <summary> /// depth first search from v /// </summary> /// <param name="g"></param> /// <param name="v"></param> private void Dfs(Graph g, int v) { _marked[v] = true; foreach (int w in g.Adj(v)) { if (_marked[w]) continue; _edgeTo[w] = v; Dfs(g, w); } }
/// <summary> /// Determines whether the undirected graph <tt>G</tt> has a cycle and, /// if so, finds such a cycle. /// </summary> /// <param name="g">g the undirected graph</param> public Cycle(Graph g) { if (HasSelfLoop(g)) return; if (HasParallelEdges(g)) return; _marked = new bool[g.V]; _edgeTo = new int[g.V]; for (var v = 0; v < g.V; v++) if (!_marked[v]) Dfs(g, -1, v); }
/// <summary> /// Returns a complete binary tree graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the binary tree</param> /// <returns>a complete binary tree graph on <tt>V</tt> vertices</returns> public static Graph BinaryTree(int v) { var g = new Graph(v); var vertices = new int[v]; for (var i = 0; i < v; i++) vertices[i] = i; StdRandom.Shuffle(vertices); for (var i = 1; i < v; i++) { g.AddEdge(vertices[i], vertices[(i - 1) / 2]); } return g; }
public void Run() { // create random bipartite graph with V vertices and E edges; then add F random edges const int vv = 20; const int e = 30; const int f = 5; var graph = new Graph(vv); var vertices = new int[vv]; for (var i = 0; i < vv; i++) vertices[i] = i; StdRandom.Shuffle(vertices); for (var i = 0; i < e; i++) { var v = StdRandom.Uniform(vv / 2); var w = StdRandom.Uniform(vv / 2); graph.AddEdge(vertices[v], vertices[vv / 2 + w]); } // add F extra edges for (var i = 0; i < f; i++) { var v = StdRandom.Uniform(vv); var w = StdRandom.Uniform(vv); graph.AddEdge(v, w); } Console.WriteLine(graph); var b = new Bipartite(graph); if (b.IsBipartite()) { Console.WriteLine("Graph is bipartite"); for (var v = 0; v < graph.V; v++) { Console.WriteLine(v + ": " + b.Color(v)); } } else { Console.Write("Graph has an odd-length cycle: "); foreach (int x in b.OddCycle()) { Console.Write(x + " "); } Console.WriteLine(); } Console.ReadLine(); }
private bool _isBipartite; // is the graph bipartite? #endregion Fields #region Constructors /// <summary> /// Determines whether an undirected graph is bipartite and finds either a /// bipartition or an odd-length cycle. /// </summary> /// <param name="g">g the graph</param> public Bipartite(Graph g) { _isBipartite = true; _color = new bool[g.V]; _marked = new bool[g.V]; _edgeTo = new int[g.V]; for (var v = 0; v < g.V; v++) { if (!_marked[v]) { Dfs(g, v); } } //assert check(G); }
public void Run() { const int vv = 20; const int e = 30; // Eulerian cycle var g1 = GraphGenerator.EulerianCycle(vv, e); EulerianCycle.UnitTest(g1, "Eulerian cycle"); // Eulerian path var g2 = GraphGenerator.EulerianCycle(vv, e); EulerianCycle.UnitTest(g2, "Eulerian path"); // empty graph var g3 = new Graph(vv); EulerianCycle.UnitTest(g3, "empty graph"); // self loop var g4 = new Graph(vv); var v4 = StdRandom.Uniform(vv); g4.AddEdge(v4, v4); EulerianCycle.UnitTest(g4, "single self loop"); // union of two disjoint cycles var h1 = GraphGenerator.EulerianCycle(vv / 2, e / 2); var h2 = GraphGenerator.EulerianCycle(vv - vv / 2, e - e / 2); var perm = new int[vv]; for (var i = 0; i < vv; i++) perm[i] = i; StdRandom.Shuffle(perm); var g5 = new Graph(vv); for (var v = 0; v < h1.V; v++) foreach (int w in h1.Adj(v)) g5.AddEdge(perm[v], perm[w]); for (var v = 0; v < h2.V; v++) foreach (int w in h2.Adj(v)) g5.AddEdge(perm[vv / 2 + v], perm[vv / 2 + w]); EulerianCycle.UnitTest(g5, "Union of two disjoint cycles"); // random digraph var g6 = GraphGenerator.Simple(vv, e); EulerianCycle.UnitTest(g6, "simple graph"); Console.ReadLine(); }
/// <summary> /// Initializes a new graph that is a deep copy of <tt>G</tt>. /// </summary> /// <param name="g">g the graph to copy</param> public Graph(Graph g) : this(g.V) { E = g.E; for (var v = 0; v < g.V; v++) { // reverse so that adjacency list is in same order as original var reverse = new Collections.Stack<Integer>(); foreach (int w in g._adj[v]) { reverse.Push(w); } foreach (int w in reverse) { _adj[v].Add(w); } } }
private readonly ST<string, Integer> _st; // string -> index #endregion Fields #region Constructors /// <summary> /// Initializes a graph from a file using the specified delimiter. /// Each line in the file contains /// the name of a vertex, followed by a list of the names /// of the vertices adjacent to that vertex, separated by the delimiter. /// </summary> /// <param name="lines">array of string lines</param> /// <param name="delimiter">delimiter the delimiter between fields</param> public SymbolGraph(IList<string> lines, char delimiter) { _st = new ST<string, Integer>(); // First pass builds the index by reading strings to associate // distinct strings with an index // while (in.hasNextLine()) { foreach (var line in lines) { var a = line.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); foreach (var word in a) { if (!_st.Contains(word)) _st.Put(word, _st.Size()); } } Console.WriteLine("Done reading"); // inverted index to get string keys in an aray _keys = new string[_st.Size()]; foreach (var name in _st.Keys()) { _keys[_st.Get(name)] = name; } // second pass builds the graph by connecting first vertex on each // line to all others G = new Graph(_st.Size()); foreach (var line in lines) { var a = line.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); int v = _st.Get(a[0]); for (var i = 1; i < a.Length; i++) { int w = _st.Get(a[i]); G.AddEdge(v, w); } } }
public void Run() { const int v = 20; const int e = 30; // Eulerian cycle var g1 = GraphGenerator.EulerianCycle(v, e); EulerianPath.UnitTest(g1, "Eulerian cycle"); // Eulerian path var g2 = GraphGenerator.EulerianPath(v, e); EulerianPath.UnitTest(g2, "Eulerian path"); // add one random edge var g3 = new Graph(g2); g3.AddEdge(StdRandom.Uniform(v), StdRandom.Uniform(v)); EulerianPath.UnitTest(g3, "one random edge added to Eulerian path"); // self loop var g4 = new Graph(v); var v4 = StdRandom.Uniform(v); g4.AddEdge(v4, v4); EulerianPath.UnitTest(g4, "single self loop"); // single edge var g5 = new Graph(v); g5.AddEdge(StdRandom.Uniform(v), StdRandom.Uniform(v)); EulerianPath.UnitTest(g5, "single edge"); // empty graph var g6 = new Graph(v); EulerianPath.UnitTest(g6, "empty graph"); // random graph var g7 = GraphGenerator.Simple(v, e); EulerianPath.UnitTest(g7, "simple graph"); Console.ReadLine(); }
/// <summary> /// Returns a random simple bipartite graph on <tt>V1</tt> and <tt>V2</tt> vertices /// with <tt>E</tt> edges. /// </summary> /// <param name="v1">V1 the number of vertices in one partition</param> /// <param name="v2">V2 the number of vertices in the other partition</param> /// <param name="e">E the number of edges</param> /// <returns>a random simple bipartite graph on <tt>V1</tt> and <tt>V2</tt> vertices, containing a total of <tt>E</tt> edges</returns> /// <exception cref="ArgumentException">if no such simple bipartite graph exists</exception> public static Graph Bipartite(int v1, int v2, int e) { if (e > (long)v1 * v2) throw new ArgumentException("Too many edges"); if (e < 0) throw new ArgumentException("Too few edges"); var g = new Graph(v1 + v2); var vertices = new int[v1 + v2]; for (var i = 0; i < v1 + v2; i++) vertices[i] = i; StdRandom.Shuffle(vertices); var set = new SET<EdgeU>(); while (g.E < e) { var i = StdRandom.Uniform(v1); var j = v1 + StdRandom.Uniform(v2); var edge = new EdgeU(vertices[i], vertices[j]); if (set.Contains(edge)) continue; set.Add(edge); g.AddEdge(vertices[i], vertices[j]); } return g; }
/// <summary> /// Computes the vertices connected to the source vertex <tt>s</tt> in the graph <tt>G</tt>. /// </summary> /// <param name="g">g the graph</param> /// <param name="s">s the source vertex</param> public NonrecursiveDFS(Graph g, int s) { _marked = new bool[g.V]; // to be able to iterate over each adjacency list, keeping track of which // vertex in each adjacency list needs to be explored next var adj = new IEnumerator<Integer>[g.V]; for (var v = 0; v < g.V; v++) adj[v] = g.Adj(v).GetEnumerator(); // depth-first search using an explicit stack var stack = new Collections.Stack<Integer>(); _marked[s] = true; stack.Push(s); while (!stack.IsEmpty()) { int v = stack.Peek(); if (adj[v].MoveNext()) { int w = adj[v].Current; // StdOut.printf("check %d\n", w); if (!_marked[w]) { // discovered vertex w for the first time _marked[w] = true; // edgeTo[w] = v; stack.Push(w); // StdOut.printf("dfs(%d)\n", w); } } else { // StdOut.printf("%d done\n", v); stack.Pop(); } } }
/// <summary> /// check optimality conditions for single source /// </summary> /// <param name="g"></param> /// <param name="s"></param> /// <returns></returns> private bool Check(Graph g, int s) { // check that the distance of s = 0 if (_distTo[s] != 0) { Console.WriteLine("distance of source " + s + " to itself = " + _distTo[s]); return false; } // check that for each edge v-w dist[w] <= dist[v] + 1 // provided v is reachable from s for (var v = 0; v < g.V; v++) { foreach (int w in g.Adj(v)) { if (HasPathTo(v) != HasPathTo(w)) { Console.WriteLine("edge " + v + "-" + w); Console.WriteLine("hasPathTo(" + v + ") = " + HasPathTo(v)); Console.WriteLine("hasPathTo(" + w + ") = " + HasPathTo(w)); return false; } if (HasPathTo(v) && (_distTo[w] > _distTo[v] + 1)) { Console.WriteLine("edge " + v + "-" + w); Console.WriteLine("distTo[" + v + "] = " + _distTo[v]); Console.WriteLine("distTo[" + w + "] = " + _distTo[w]); return false; } } } // check that v = edgeTo[w] satisfies distTo[w] + distTo[v] + 1 // provided v is reachable from s for (var w = 0; w < g.V; w++) { if (!HasPathTo(w) || w == s) continue; var v = _edgeTo[w]; if (_distTo[w] == _distTo[v] + 1) continue; Console.WriteLine("shortest path edge " + v + "-" + w); Console.WriteLine("distTo[" + v + "] = " + _distTo[v]); Console.WriteLine("distTo[" + w + "] = " + _distTo[w]); return false; } return true; }
/// <summary> /// breadth-first search from multiple sources /// </summary> /// <param name="g"></param> /// <param name="sources"></param> private void Bfs(Graph g, IEnumerable<Integer> sources) { var q = new Collections.Queue<Integer>(); foreach (int s in sources) { _marked[s] = true; _distTo[s] = 0; q.Enqueue(s); } while (!q.IsEmpty()) { int v = q.Dequeue(); foreach (int w in g.Adj(v)) { if (_marked[w]) continue; _edgeTo[w] = v; _distTo[w] = _distTo[v] + 1; _marked[w] = true; q.Enqueue(w); } } }
/// <summary> /// breadth-first search from a single source /// </summary> /// <param name="g"></param> /// <param name="s"></param> private void Bfs(Graph g, int s) { var q = new Collections.Queue<Integer>(); for (var v = 0; v < g.V; v++) _distTo[v] = INFINITY; _distTo[s] = 0; _marked[s] = true; q.Enqueue(s); while (!q.IsEmpty()) { int v = q.Dequeue(); foreach (int w in g.Adj(v)) { if (_marked[w]) continue; _edgeTo[w] = v; _distTo[w] = _distTo[v] + 1; _marked[w] = true; q.Enqueue(w); } } }
/// <summary> /// Determines whether a digraph has an Eulerian path using necessary /// and sufficient conditions (without computing the path itself): /// - indegree(v) = outdegree(v) for every vertex, /// except one vertex v may have outdegree(v) = indegree(v) + 1 /// (and one vertex v may have indegree(v) = outdegree(v) + 1) /// - the graph is connected, when viewed as an undirected graph /// (ignoring isolated vertices) /// This method is solely for unit testing. /// </summary> /// <param name="g"></param> /// <returns></returns> private static bool HasEulerianPath(Digraph g) { if (g.E == 0) return true; // Condition 1: indegree(v) == outdegree(v) for every vertex, // except one vertex may have outdegree(v) = indegree(v) + 1 var deficit = 0; for (var v = 0; v < g.V; v++) if (g.Outdegree(v) > g.Indegree(v)) deficit += (g.Outdegree(v) - g.Indegree(v)); if (deficit > 1) return false; // Condition 2: graph is connected, ignoring isolated vertices var h = new Graph(g.V); for (var v = 0; v < g.V; v++) foreach (int w in g.Adj(v)) h.AddEdge(v, w); // check that all non-isolated vertices are connected var s = NonIsolatedVertex(g); var bfs = new BreadthFirstPaths(h, s); for (var v = 0; v < g.V; v++) if (h.Degree(v) > 0 && !bfs.HasPathTo(v)) return false; return true; }
private bool Check(Graph g) { // graph is bipartite if (_isBipartite) { for (var v = 0; v < g.V; v++) { foreach (int w in g.Adj(v)) { if (_color[v] != _color[w]) continue; Console.Error.WriteLine($"edge {v}-{w} with {v} and {w} in same side of bipartition\n"); return false; } } } // graph has an odd-length cycle else { // verify cycle int first = -1, last = -1; foreach (int v in OddCycle()) { if (first == -1) first = v; last = v; } if (first == last) return true; Console.Error.WriteLine($"cycle begins with {first} and ends with {last}{Environment.NewLine}"); return false; } return true; }
/// <summary> /// Determines whether a graph has an Eulerian path using necessary /// and sufficient conditions (without computing the path itself): /// - degree(v) is even for every vertex, except for possibly two /// - the graph is connected (ignoring isolated vertices) /// This method is solely for unit testing. /// </summary> /// <param name="g"></param> /// <returns></returns> private static bool HasEulerianPath(Graph g) { if (g.E == 0) return true; // Condition 1: degree(v) is even except for possibly two var oddDegreeVertices = 0; for (var v = 0; v < g.V; v++) if (g.Degree(v) % 2 != 0) oddDegreeVertices++; if (oddDegreeVertices > 2) return false; // Condition 2: graph is connected, ignoring isolated vertices var s = NonIsolatedVertex(g); var bfs = new BreadthFirstPaths(g, s); for (var v = 0; v < g.V; v++) if (g.Degree(v) > 0 && !bfs.HasPathTo(v)) return false; return true; }
private readonly Collections.Stack<Integer> _path; // Eulerian path; null if no suh path #endregion Fields #region Constructors /// <summary> /// Computes an Eulerian path in the specified graph, if one exists. /// </summary> /// <param name="g">g the graph</param> public EulerianPath(Graph g) { // find vertex from which to start potential Eulerian path: // a vertex v with odd degree(v) if it exits; // otherwise a vertex with degree(v) > 0 var oddDegreeVertices = 0; var s = NonIsolatedVertex(g); for (var v = 0; v < g.V; v++) { if (g.Degree(v) % 2 != 0) { oddDegreeVertices++; s = v; } } // graph can't have an Eulerian path // (this condition is needed for correctness) if (oddDegreeVertices > 2) return; // special case for graph with zero edges (has a degenerate Eulerian path) if (s == -1) s = 0; // create local view of adjacency lists, to iterate one vertex at a time // the helper Edge data type is used to avoid exploring both copies of an edge v-w var adj = new Collections.Queue<EdgeW>[g.V]; for (var v = 0; v < g.V; v++) adj[v] = new Collections.Queue<EdgeW>(); for (var v = 0; v < g.V; v++) { var selfLoops = 0; foreach (int w in g.Adj(v)) { // careful with self loops if (v == w) { if (selfLoops % 2 == 0) { var e = new EdgeW(v, w, 0); adj[v].Enqueue(e); adj[w].Enqueue(e); } selfLoops++; } else if (v < w) { var e = new EdgeW(v, w, 0); adj[v].Enqueue(e); adj[w].Enqueue(e); } } } // initialize stack with any non-isolated vertex var stack = new Collections.Stack<Integer>(); stack.Push(s); // greedily search through edges in iterative DFS style _path = new Collections.Stack<Integer>(); while (!stack.IsEmpty()) { int v = stack.Pop(); while (!adj[v].IsEmpty()) { var edge = adj[v].Dequeue(); if (edge.IsUsed) continue; edge.IsUsed = true; stack.Push(v); v = edge.Other(v); } // push vertex with no more leaving edges to path _path.Push(v); } // check if all edges are used if (_path.Size() != g.E + 1) _path = null; //assert certifySolution(G); }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyCG.txt"); // Prompt Console.WriteLine("2 - mediumG.txt"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); var fieName = string.Empty; switch (fileNumber) { case "1": fieName = "tinyCG.txt"; break; case "2": fieName = "mediumG.txt"; break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fieName}"); var lines = @in.ReadAllLines(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<EdgeU>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var edge = new EdgeU(ve, we); edges.Add(edge); } lineIterator++; } var graph = new Graph(v, e, edges); Console.WriteLine(graph); const int s = 0; var dfs1 = new DepthFirstPaths(graph, s); for (var vi = 0; vi < graph.V; vi++) { if (dfs1.HasPathTo(vi)) { Console.Write($"{s} to {vi}: "); foreach (int x in dfs1.PathTo(vi)) { if (x == s) Console.Write(x); else Console.Write($"-{x}"); } Console.WriteLine(); } else { Console.WriteLine($"{s} to {v}: not connected{Environment.NewLine}"); } } //Console.WriteLine("------------------------------------------------"); Console.ReadLine(); }
// check that solution is correct public bool CertifySolution(Graph g) { // internal consistency check if (HasEulerianPath() == (Path() == null)) return false; // hashEulerianPath() returns correct value if (HasEulerianPath() != HasEulerianPath(g)) return false; // nothing else to check if no Eulerian path if (_path == null) return true; // check that path() uses correct number of edges if (_path.Size() != g.E + 1) return false; // check that path() is a path in G // TODO return true; }
public void Run() { Console.WriteLine("Choose file:"); // Prompt Console.WriteLine("1 - tinyG.txt"); // Prompt Console.WriteLine("2 - mediumG.txt"); // Prompt //Console.WriteLine("3 - largeG.zip"); // Prompt Console.WriteLine("or quit"); // Prompt var fileNumber = Console.ReadLine(); var fieName = string.Empty; switch (fileNumber) { case "1": fieName = "tinyG.txt"; break; case "2": fieName = "mediumG.txt"; break; //case "3": // fieName = "largeG.zip"; // break; case "quit": return; default: return; } var @in = new In($"Files\\Graphs\\{fieName}"); var lines = !fieName.EndsWith("zip") ? @in.ReadAllLines() : @in.ReadAllLinesFromZip(); var lineIterator = 0; var v = 0; var e = 0; var edges = new List<EdgeU>(); foreach (var line in lines) { if (lineIterator == 0) { v = Convert.ToInt32(line); } if (lineIterator == 1) { e = Convert.ToInt32(line); } if (lineIterator > 1) { var lineSplitted = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var ve = Convert.ToInt32(lineSplitted[0]); var we = Convert.ToInt32(lineSplitted[1]); var edge = new EdgeU(ve, we); edges.Add(edge); } lineIterator++; } var graph = new Graph(v, e, edges); if (fileNumber != "3") { Console.WriteLine(graph); } var finder = new Cycle(graph); if (finder.HasCycle()) { foreach (int vi in finder.CycleIterator()) { Console.Write($"{vi} "); } Console.WriteLine(); } else { Console.WriteLine("Graph is acyclic"); } Console.ReadLine(); }
private void Bfs(Graph g, int s) { var q = new Collections.Queue<Integer>(); _color[s] = WHITE; _marked[s] = true; q.Enqueue(s); while (!q.IsEmpty()) { int v = q.Dequeue(); foreach (int w in g.Adj(v)) { if (!_marked[w]) { _marked[w] = true; _edgeTo[w] = v; _color[w] = !_color[v]; q.Enqueue(w); } else if (_color[w] == _color[v]) { _isBipartite = false; // to form odd cycle, consider s-v path and s-w path // and let x be closest node to v and w common to two paths // then (w-x path) + (x-v path) + (edge v-w) is an odd-length cycle // Note: distTo[v] == distTo[w]; _cycle = new Collections.Queue<Integer>(); var stack = new Collections.Stack<Integer>(); int x = v, y = w; while (x != y) { stack.Push(x); _cycle.Enqueue(y); x = _edgeTo[x]; y = _edgeTo[y]; } stack.Push(x); while (!stack.IsEmpty()) _cycle.Enqueue(stack.Pop()); _cycle.Enqueue(w); return; } } } }
private void Dfs(Graph g, int v) { _marked[v] = true; foreach (int w in g.Adj(v)) { // short circuit if odd-length cycle found if (_cycle != null) return; // found uncolored vertex, so recur if (!_marked[w]) { _edgeTo[w] = v; _color[w] = !_color[v]; Dfs(g, w); } // if v-w create an odd-length cycle, find it else if (_color[w] == _color[v]) { _isBipartite = false; _cycle = new Collections.Stack<Integer>(); _cycle.Push(w); // don't need this unless you want to include start vertex twice for (var x = v; x != w; x = _edgeTo[x]) { _cycle.Push(x); } _cycle.Push(w); } } }
public static void UnitTest(Graph g, string description) { Console.WriteLine(description); Console.WriteLine("-------------------------------------"); Console.Write(g); var euler = new EulerianPath(g); Console.Write("Eulerian path: "); if (euler.HasEulerianPath()) { foreach (int v in euler.Path()) { Console.Write($"{v} "); } Console.WriteLine(); } else { Console.WriteLine("none"); } Console.WriteLine(); }
// returns any non-isolated vertex; -1 if no such vertex private static int NonIsolatedVertex(Graph g) { for (var v = 0; v < g.V; v++) if (g.Degree(v) > 0) return v; return -1; }