package com.e2u.alg.match;
import java.util.ArrayList;
import java.util.Iterator;
public class Edmonds {
private ArrayList<Node> cycle;
public AdjacencyList getMinBranching(Node root, AdjacencyList list){
AdjacencyList reverse = list.getReversedList();
// remove all edges entering the root
if(reverse.getAdjacent(root) != null){
reverse.getAdjacent(root).clear();
}
AdjacencyList outEdges = new AdjacencyList();
// for each node, select the edge entering it with smallest weight
for(Node n : reverse.getSourceNodeSet()){
ArrayList<Edge> inEdges = reverse.getAdjacent(n);
if(inEdges.isEmpty()) continue;
Edge min = inEdges.get(0);
for(Edge e : inEdges){
if(e.weight < min.weight){
min = e;
}
}
outEdges.addEdge(min.to, min.from, min.weight);
}
// detect cycles
ArrayList<ArrayList<Node>> cycles = new ArrayList<ArrayList<Node>>();
cycle = new ArrayList<Node>();
getCycle(root, outEdges);
cycles.add(cycle);
for(Node n : outEdges.getSourceNodeSet()){
if(!n.visited){
cycle = new ArrayList<Node>();
getCycle(n, outEdges);
cycles.add(cycle);
}
}
// for each cycle formed, modify the path to merge it into another part of the graph
AdjacencyList outEdgesReverse = outEdges.getReversedList();
for(ArrayList<Node> x : cycles){
if(x.contains(root)) continue;
mergeCycles(x, list, reverse, outEdges, outEdgesReverse);
}
return outEdges;
}
private void mergeCycles(ArrayList<Node> cycle, AdjacencyList list, AdjacencyList reverse, AdjacencyList outEdges, AdjacencyList outEdgesReverse){
ArrayList<Edge> cycleAllInEdges = new ArrayList<Edge>();
Edge minInternalEdge = null;
// find the minimum internal edge weight
for(Node n : cycle){
for(Edge e : reverse.getAdjacent(n)){
if(cycle.contains(e.to)){
if(minInternalEdge == null || minInternalEdge.weight > e.weight){
minInternalEdge = e;
continue;
}
}else{
cycleAllInEdges.add(e);
}
}
}
// find the incoming edge with minimum modified cost
Edge minExternalEdge = null;
int minModifiedWeight = 0;
for(Edge e : cycleAllInEdges){
int w = e.weight - (outEdgesReverse.getAdjacent(e.from).get(0).weight - minInternalEdge.weight);
if(minExternalEdge == null || minModifiedWeight > w){
minExternalEdge = e;
minModifiedWeight = w;
}
}
// add the incoming edge and remove the inner-circuit incoming edge
Edge removing = outEdgesReverse.getAdjacent(minExternalEdge.from).get(0);
outEdgesReverse.getAdjacent(minExternalEdge.from).clear();
outEdgesReverse.addEdge(minExternalEdge.to, minExternalEdge.from, minExternalEdge.weight);
ArrayList<Edge> adj = outEdges.getAdjacent(removing.to);
for(Iterator<Edge> i = adj.iterator(); i.hasNext(); ){
if(i.next().to == removing.from){
i.remove();
break;
}
}
outEdges.addEdge(minExternalEdge.to, minExternalEdge.from, minExternalEdge.weight);
}
private void getCycle(Node n, AdjacencyList outEdges){
n.visited = true;
cycle.add(n);
if(outEdges.getAdjacent(n) == null) return;
for(Edge e : outEdges.getAdjacent(n)){
if(!e.to.visited){
getCycle(e.to, outEdges);
}
}
}
}