Start implementation of matching algorithm
This commit is contained in:
parent
a35d86d0d4
commit
e568e298f0
2 changed files with 79 additions and 3 deletions
74
edmonds.cpp
74
edmonds.cpp
|
@ -1,8 +1,76 @@
|
||||||
#include "edmonds.h"
|
#include "edmonds.h"
|
||||||
|
|
||||||
namespace Edmonds {
|
using namespace ED;
|
||||||
ED::Graph maximum_matching(ED::Graph & graph)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
namespace Edmonds {
|
||||||
|
|
||||||
|
std::vector<NodeId> path_to_forest_root(Graph const & graph, NodeId id)
|
||||||
|
{
|
||||||
|
std::vector<NodeId> retval;
|
||||||
|
retval.push_back(id);
|
||||||
|
while (graph.matched_neighbor(id) != id)
|
||||||
|
{
|
||||||
|
id = graph.matched_neighbor(id);
|
||||||
|
retval.push_back(id);
|
||||||
|
|
||||||
|
// Note that it is guaranteed that this does not produce a loop:
|
||||||
|
// We are traversing the path to a root of the forest,
|
||||||
|
// but we know that each root is exposed by M, so after traversing
|
||||||
|
// the matching edge, we cannot have reached a root.
|
||||||
|
id = graph.ear_or_root_neighbor(id);
|
||||||
|
retval.push_back(id);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Graph maximum_matching(Graph & graph)
|
||||||
|
{
|
||||||
|
graph.reset_forest();
|
||||||
|
for(NodeId id = 0; id < graph.num_nodes(); ++id) {
|
||||||
|
if (graph.is_out_of_forest(id))
|
||||||
|
{
|
||||||
|
for(NodeId neighbor_id : graph.node(id).neighbors())
|
||||||
|
{
|
||||||
|
if (graph.is_out_of_forest(neighbor_id))
|
||||||
|
{
|
||||||
|
// Grow Forest
|
||||||
|
graph.node(neighbor_id).ear_or_root_neighbor = id;
|
||||||
|
}
|
||||||
|
else if (graph.is_outer(neighbor_id) and \
|
||||||
|
graph.root_of_ear_component(id) != graph.root_of_ear_component(neighbor_id))
|
||||||
|
{
|
||||||
|
std::vector<NodeId> x_path = path_to_forest_root(graph, id);
|
||||||
|
std::vector<NodeId> y_path = path_to_forest_root(graph, neighbor_id);
|
||||||
|
|
||||||
|
if (x_path.back() != y_path.back())
|
||||||
|
{
|
||||||
|
// Paths are disjoint -> augment
|
||||||
|
graph.node(x_path.front()).matched_neighbor = y_path.front();
|
||||||
|
graph.node(y_path.front()).matched_neighbor = x_path.front();
|
||||||
|
|
||||||
|
// TODO: put this into own method?
|
||||||
|
for(size_t i = 1; i < x_path.size(); i += 2)
|
||||||
|
{
|
||||||
|
graph.node(x_path[i]).matched_neighbor = x_path[i+1];
|
||||||
|
graph.node(x_path[i+1]).matched_neighbor = x_path[i];
|
||||||
|
}
|
||||||
|
for(size_t i = 1; i < y_path.size(); i += 2)
|
||||||
|
{
|
||||||
|
graph.node(y_path[i]).matched_neighbor = y_path[i+1];
|
||||||
|
graph.node(y_path[i+1]).matched_neighbor = y_path[i];
|
||||||
|
}
|
||||||
|
// Note that since this is tail-recursion, this will not generate
|
||||||
|
// new stack frames in OPT mode
|
||||||
|
return maximum_matching(graph);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Paths are not disjoint -> shrink blossom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -146,6 +146,8 @@ public:
|
||||||
**/
|
**/
|
||||||
Node const & node(NodeId const id) const;
|
Node const & node(NodeId const id) const;
|
||||||
|
|
||||||
|
Node & node(NodeId const id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Adds the edge <tt> {node1_id, node2_id} </tt> to this graph.
|
@brief Adds the edge <tt> {node1_id, node2_id} </tt> to this graph.
|
||||||
|
|
||||||
|
@ -224,6 +226,12 @@ Node const & Graph::node(NodeId const id) const
|
||||||
{
|
{
|
||||||
return _nodes[id];
|
return _nodes[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
Node & Graph::node(NodeId const id)
|
||||||
|
{
|
||||||
|
return _nodes[id];
|
||||||
|
}
|
||||||
//END: Inline section
|
//END: Inline section
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue