small cycle finding in a planar graph - algorithm

I have a geometric undirected planar graph, that is a graph where each node has a location and no 2 edges cross, and I want to find all cycles that have no edges crossing them.
Are there any good solutions known to this problem?
What I'm planning on doing is a sort of A* like solution:
insert every edge in a min heap as a path
extend the shortest path with every option
cull paths that loop back to other than there start (might not be needed)
cull paths that would be the third to use ang given edge
Does anyone see an issue with this? Will it even work?

My first instinct is to use a method similar to a wall following maze solver. Essentially, follow edges, and always take the rightmost edge out of a vertex. Any cycles you encounter with this method will be boundaries of a face. You'll have to keep track of which edges you've traversed in which direction. Once you've traversed an edge in both directions, you've identified the faces it separates. Once all edges have been traversed in both directions, you'll have identified all faces by their boundaries.

A "crossing edge", as you call it, is generally known as a chord. Thus, your problem is to find all chordless cycles.
This paper looks like it may help.

A simple way to do this is to simply go out and enumerate each face. The principle is simple:
We maintain 'α-visited' and 'β-visited' flags for each edge, and a pair of doubly-linked lists of unvisited edges for each such flag. The 'α' and 'β' division should correspond to a partition of the plane on the line corresponding to the edge in question; which side is α and which side is β is arbitrary.
For each vertex V:
For each adjacent pair of edges E = (V_1, V), E'=(V_2, V) (ie, sort by angle, take adjacent pairs, as well as first+last):
Determine which side S of E (S=α or β) V_2 lies on.
Walk the tile, starting at V, using side S of E, as described below:
Walking the tile is performed by:
Let V = V_init
Loop:
V_next = the vertex of E that is not V
E' = The adjacent edge to E from V_next that is on the current side of E
S' = The side of E' that contains V
If V_next = V, we have found a loop; record all the edges we passed by on the way, and mark those edge-pairs as visited.
If E' = E (there is only one edge), then we have hit a dead end; abort this walk
Otherwise, let V = V_next, E = E', S = S' and continue.
I hope this made sense; it perhaps needs some diagrams to explain...

Related

Dynamic Programming - Edges difference problem

I just started learning about Dynamic Programming, and in my assignment I was required to describe an algorithm that solves the following problem:
Let G be a directed graph, where every edge is colored either green or yellow, and a source vertex s. For every vertex in V, find a path that the difference between the number of green and yellow edges is minimal. That algorithm needs to be O(|V|+|E|) complexity for each vertex.
Input: Given a directed graph G=(V, E), a source vertex s in V and edges colored with this coloring function: For every edge e in the graph, c(e)->{yellow, green}. There is a path to every vertex v in V from the source vertex s.
The weight of a path 'P' in the graph, is the difference between the number of green edges and the number of yellow edges in the graph
Output: For every vertex v in V, return the minimal weight of a path P from s to v.
So I started thinking about a solution to this problem. I realized that I can exchange the colors with numbers, -1 and 1 and work from there, but so far I haven't been able to find a solution.
My most fleshed out solution looks at the group of neighbors of target a vertex and does the following:
Find the minimum weight between:
The sum of the "weight" of the edge (-1, 1) leading to a vertex 'k' from the current vertex's neighbor group, and the optimum of 'k'.
The optimum of the other neighbors, excluding the vertex 'k'.
terminate when reaching s or the neighbors group is empty.
However, this solution doesn't feel right, as it doesn't look at a vertex - but at a group of vertices, and I don't think it meets the complexity demands. I tried writing the formula: image
I tried experimenting with solutions that start from the vertex s and end at a target vertex v, but I was unable to reach a solid termination condition. For example, it can't terminate when reaching v, since there might be cycles involving v that result in a minimum result.
I was hoping to get some guidance on this problem, thanks in advance!
This doesn't necessarily strike me as a case for dynamic programming, so maybe I've missed something and there's a quicker dynamic solution, but you can achieve an O(VE) running time using a modified Bellman-Ford. This asymptotic time bound is not the same as O(V + E) per vertex! But for a connected graph (since the source can reach all the vertices) it is the same overall.
I'll leave you to look up the details of the Bellman Ford algorithm (for single source shortest paths), in the spirit of it being an assignment, but suffice it to say that your vertices could store a positive score for more yellow than green, a negative score for the opposite, and their weight in either case would be the absolute value of this attribute. Your 'relax' function would then operate as follows, assuming we use a score attribute on each vertex (this score is not the weight, it can be positive or negative):
RELAX(u, v):
new_score = u.score
if the edge u -> v is green:
new_score -= 1
else:
new_score += 1
if abs(new_score) < v.score:
v.score = new_score

Difficulties understanding, bipartite graphs

I am looking back at some of my algorithms homework(exam soon haha), and I am having troubles understanding the solution to one of the questions.
The Question
Tutor Solution
I am having difficulties visualizing the solution, I understand that if you have an odd number of cycles than your graph cannot be bipartite. But as I stated, I don't understand the shortest path from s to u and v to s.
Let's say G is bipartite. Then the vertex set can be divided into V1 and V2 s.t. every edge of G includes a vertex from each set. Then the vertices of every path in G alternate between V1 and V2, so the parity of the length of every path between every pair of vertices is the same. I.e., if G is bipartite and v,w are two vertices of G, then the length of every path connecting v & w is either even or odd.
If there is an edge (u,v) connecting two vertices in the same layer then this is violated. The BFS path to v and u have the same length, so same parity, since v & u are in the same layer. The edge between v & u gives us a path longer by 1, so of a different parity. Contradiction.
The tutor's solution isn't as clear as it could be, since it talks about cycles, and the two paths don't necessarily form a cycle since they can share vertices. And the definition of bipartite graph is slightly wrong (or uses non-standard definitions of edges, cross-product etc. where the things aren't pairs but 2-element sets).
But instead of the definition as given, I'd just say that a graph is bipartite if the vertices can be coloured black or white, such that each edge goes between different-coloured vertices. (Equivalently you can simply say "the graph is 2-colourable").
From this definition, it follows that if there's an even length path between two vertices they must be the same colour, otherwise different colours. In the BFS on a bipartite graph, a vertex u is layer i has a path of length i from s to u, so all vertices in the same layer have the same colour. Thus there can be no edge between two vertices in the same layer.

Finding negative cycle in undirected graph

I tried googling it up, but nothing of value pops up.
The graph:
is undirected.
is represented as directed graph with double edges.
may contain edges with negative weights.
I know I can use Bellman-Ford to solve this in the directed case, but with undirected edges it will just return single edges (2-cycles) as its output. I need to find a cycle of size > 2.
Also, the algorithm is supposed to have run-time complexity O(V*E) and memory complexity O(V).
Looking at the Bellman-Ford algorithm, in step 2 you consider using every edge (u, v) to to find a shorter path to v and, if you see an improvement, you record it by setting predecessor[v] = u. This means that at each stage you know the predecessor of each node - so you can eliminate length two cycles by checking that predecessor[u] != v before you set predecessor[v] = u.
By eliminating these cycles you change the invariant of the induction - at each stage you are now finding the shortest route to u from s with at most i edges which does not include any length 2 cycles.
A cycle of length 3 or greater reachable from the source should still show up - the check for negative cycles looks for apparent improvements after you should have found every shortest path for lengths up to that necessary to visit every vertex.
Example:Consider G = {{A, B, C, D}, {AB=2, AC=2, BC=-3, BD=1, CD=1}}.
Updates, updating B then C then D:
A=0, B=C=D=infinity
A=0, B=2 from A, C=-1 from B, D=0 from C
A=0, B=1 from D, C=-2 from B, D=-1 from C
A=0, B=0 from D, C=-3 from B, D=-2 from C
A=-1 from C, B=-1 from D, C=-4 from B, D=-3 from C
...
Here is a proof that the distances will continue changing indefinitely in the presence of a negative cycle:
Suppose otherwise. Then there is an assignment of distances which is stable: no possible updating of any distance will decrease it. This means that the order in which edges are checked which might decrease a distance is irrelevant, since for this to be the case, every edge, when checked, leaves the distances unchanged.
Pick a point on a negative cycle and consider the path that goes along from that point until it wraps round and reaches itself again. Since checking the first edge in this path leaves everything unchanged, the distance at the far end of that edge minus the distance at the near end of that edge must be no more than the distance along the edge. Similarly, the distance two steps along the path minus the distance at the start of the path must be no more than the sum of the distances along the two edges concerned, or we would update the distance to the further of the two points. Carrying on, we work out that the distance at the end of the (circular) path must be no more than the start of the (circular path) plus the sum of the edges along that path, or something would have been updated. But the start and end of the path are the same point, because it is circular, and the sum of the distances along the edges is negative, because it is a negative cycle, so we reach a contradiction and there must in fact be some updating once we have checked all the edges along the circular path.

Find all edges in min-cut

Let (G,s,t,{c}) be a flow network, and let F be the set of all edges e for which there exists at least one minimum cut (A,B) such that e goes from A to B. Give a polynomial time algorithm that finds all edges in F.
NOTE: So far I know I need to run Ford-Fulkerson so each edges has a flow. Furthermore I know for all edges in F, the flow f(e) = c(e). However not all edges in a graph G which respects that constraint will be in a min-cut. I am stuck here.
Suppose you have computed a max flow on a graph G and you know the flow through every edge in the graph. From the source vertex s, perform a Breadth First Search OR Depth First Search on the original graph and only traverse those edges that have flow less than the capacity of the edge. Denote the set of vertices reachable in this traversal as S, and unreachable vertices as T.
To obtain the minimum cut C, we simply find all edges in the original graph G which begin at some vertex in S and end at some vertex in T.
This tutorial in Topcoder provides an explanation / proof of the above algorithm. Look at the section beginning with the following text:
A cut in a flow network is simply a partition of the vertices in two sets, let's call them A and B, in such a way that the source vertex is in A and the sink is in B.
I shall attempt to provide an explanation of the corresponding section in the Topcoder tutorial (just for me to brush up on this as well).
Now, suppose that we have computed a max flow on a graph G, and that we have computed the set of edges C using the procedure outlined above. From here, we can conclude several facts.
Fact 1: Source vertex s must be in set S, and sink vertex t must be in set T.
Otherwise, vertices s and t must be in the same set, which means that we must have found a path from s to t consisting only of edges that have flow less than capacity. This means that we can push more flow from s to t, and therefore we have found an augmenting path! However, this is a contradiction, since we have already computed a max flow on the graph. Hence, it is impossible for source vertex s and sink vertex t to be connected, and they must be in different sets.
Fact 2: Every edge beginning at set S and ending at set T must have flow == capacity
Again we prove this by contradiction. Suppose that there is a vertex u in S and a vertex v in T, such that edge (u,v) in the residual network has flow less than capacity. By our algorithm above, this edge will be traversed, and vertex v should be in set S. This is a contradiction. Therefore, such an edge must have flow == capacity.
Fact 3: Removing the edges in C from graph G will mean that there is no path from any vertex in set S to any vertex in set T
Suppose that this is not the case, and there is some edge (u,v) that connects vertex u in set S to vertex v in set T. We can separate this into 2 cases:
Flow through edge (u,v) is less than its capacity. But we know this will cause vertex v to be part of set S, so this case is impossible.
Flow through edge (u,v) is equal to its capacity. This is impossible since edge (u,v) will be considered as part of the edge set C.
Hence both cases are impossible, and we see that removing the edges in C from the original graph G will indeed result in a situation where there is no path from S to T.
Fact 4: Every edge in the original graph G that begins at vertex set T but ends at vertex set S must have a flow of 0
The explanation on the Topcoder tutorial may not be obvious on first reading and the following is an educated guess on my part and may be incorrect.
Suppose that there exists some edge (x,y) (where x belongs to vertex set T and y belongs to vertex set S), such that the flow through (x,y) is greater than 0. For convenience, we denote the flow through (x,y) as f. This means that on the residual network, there must exist a backward edge (y,x) with capacity f and flow 0. Since vertex y is part of set S, the backward edge (y,x) has flow 0 with capacity f > 0, our algorithm will traverse the edge (y,x) and place vertex x as part of vertex set S. However, we know that vertex x is part of vertex set T, and hence this is a contradiction. As such, all edges from T to S must have a flow of 0.
With these 4 facts, along with the Max-flow min-cut theorem, we can conclude that:
The max flow must be less than or equal to the capacity of any cut. By Fact 3, C is a cut of the graph, so the max flow must be less than or equal to the capacity of cut C.
Fact 4 allows us to conclude that there is no "back flow" from T to S. This along with Fact 2 means that the flow consists entirely of "forward flow" from S to T. In particular, all the forward flow must result from the cut C. This flow value happens to be the max flow. As such, by the Max-flow min-cut theorem, we know that C must be a minimum cut.

How do I partition a bipartite graph by color?

For instance, suppose I have a graph G = (V, E) where
V = {A, B, C, D}
E = {(A, B), (A,D), (C, D)}
This graph is bipartite, and thus can be split into two disjoint sets {A, C} and {B, D}. My first guess is that I can simply walk the graph and assign alternating colors to each vertex. Is this the case, or is it more complicated/simpler than this? Are there any known algorithms for this?
Your first guess is correct - traverse the graph and alternate.
The algorithm should be simple. I'd keep two queues of nodes to visit, one for each colour. Pop nodes off the queues alternately, mark its colour, and push any non-visited adjacent nodes into the queue for the opposite colour. Terminate when the number of visited nodes + the length of both queues = number of nodes in the graph.
From Wikipedia (http://en.wikipedia.org/wiki/Bipartite_graph)
If a bipartite graph is connected, its bipartition can be defined by the parity of the distances from any arbitrarily chosen vertex v: one subset consists of the vertices at even distance to v and the other subset consists of the vertices at odd distance to v.
Thus, one may efficiently test whether a graph is bipartite by using this parity technique to assign vertices to the two subsets U and V, separately within each connected component of the graph, and then examine each edge to verify that it has endpoints assigned to different subsets.
Traverse the graph and alternate, if it doesn't succeded it means that your graph is not bipartite.
If you are sure that the graph is biparte, then you can just assign colors alternating them for traversing each vertex, as it holds that:
A graph is bipartite if and only if it is 2-colorable.
I implemented it in my graph drawing tool, you can see my code in JavaScript.
I just marked first vertex as left partity, then recursively marked it's neighbours as right partity, recursively mark their neighbours as left partity... If you find correctly marked node, stop recursion of this branch. If you find uncorrectly marked node, graph is not bipartite.
Maybe it can be done simpler, but during last few months I had some hard Prolog - Haskell coding days, maybe it had affected my brain and now I see recursion in everything :-D
Just in case anyone's curious, here's the code I came up with:
def dfs(root, colorings):
to_visit1 = deque()
to_visit2 = deque()
to_visit1.append(root)
while len(to_visit1) != 0 or len(to_visit2) != 0:
dfs_color(to_visit1, to_visit2, True, colorings)
dfs_color(to_visit2, to_visit1, False, colorings)
def dfs_color(queue, opposite_queue, color, colorings):
while len(queue) != 0:
v = queue.pop()
if v in adjacency_list:
colorings[v] = color
neighbors = adjacency_list[v]
del adjacency_list[v]
for neighbor in neighbors:
opposite_queue.append(neighbor)
Admittedly, this isn't my best code. I'm using True/False as the color because when I used recursion, it made it easy to just say not color. Of course, I had to change it because I blew my stack on bigger graphs. Also to give credit where due, this code is based on the wikipedia code for DFS.
Although as has been pointed out, I think this may just be a disguised BFS.

Resources