| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 | //=======================================================================// Copyright 2007 Aaron Windsor//// Distributed under the Boost Software License, Version 1.0. (See// accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)//=======================================================================#ifndef __IS_KURATOWSKI_SUBGRAPH_HPP__#define __IS_KURATOWSKI_SUBGRAPH_HPP__#include <boost/config.hpp>#include <boost/tuple/tuple.hpp> //for tie#include <boost/property_map/property_map.hpp>#include <boost/graph/properties.hpp>#include <boost/graph/isomorphism.hpp>#include <boost/graph/adjacency_list.hpp>#include <algorithm>#include <vector>#include <set>namespace boost{namespace detail{    template < typename Graph > Graph make_K_5()    {        typename graph_traits< Graph >::vertex_iterator vi, vi_end, inner_vi;        Graph K_5(5);        for (boost::tie(vi, vi_end) = vertices(K_5); vi != vi_end; ++vi)            for (inner_vi = next(vi); inner_vi != vi_end; ++inner_vi)                add_edge(*vi, *inner_vi, K_5);        return K_5;    }    template < typename Graph > Graph make_K_3_3()    {        typename graph_traits< Graph >::vertex_iterator vi, vi_end,            bipartition_start, inner_vi;        Graph K_3_3(6);        bipartition_start = next(next(next(vertices(K_3_3).first)));        for (boost::tie(vi, vi_end) = vertices(K_3_3); vi != bipartition_start;             ++vi)            for (inner_vi = bipartition_start; inner_vi != vi_end; ++inner_vi)                add_edge(*vi, *inner_vi, K_3_3);        return K_3_3;    }    template < typename AdjacencyList, typename Vertex >    void contract_edge(AdjacencyList& neighbors, Vertex u, Vertex v)    {        // Remove u from v's neighbor list        neighbors[v].erase(            std::remove(neighbors[v].begin(), neighbors[v].end(), u),            neighbors[v].end());        // Replace any references to u with references to v        typedef            typename AdjacencyList::value_type::iterator adjacency_iterator_t;        adjacency_iterator_t u_neighbor_end = neighbors[u].end();        for (adjacency_iterator_t u_neighbor_itr = neighbors[u].begin();             u_neighbor_itr != u_neighbor_end; ++u_neighbor_itr)        {            Vertex u_neighbor(*u_neighbor_itr);            std::replace(neighbors[u_neighbor].begin(),                neighbors[u_neighbor].end(), u, v);        }        // Remove v from u's neighbor list        neighbors[u].erase(            std::remove(neighbors[u].begin(), neighbors[u].end(), v),            neighbors[u].end());        // Add everything in u's neighbor list to v's neighbor list        std::copy(neighbors[u].begin(), neighbors[u].end(),            std::back_inserter(neighbors[v]));        // Clear u's neighbor list        neighbors[u].clear();    }    enum target_graph_t    {        tg_k_3_3,        tg_k_5    };} // namespace detailtemplate < typename Graph, typename ForwardIterator, typename VertexIndexMap >bool is_kuratowski_subgraph(const Graph& g, ForwardIterator begin,    ForwardIterator end, VertexIndexMap vm){    typedef typename graph_traits< Graph >::vertex_descriptor vertex_t;    typedef typename graph_traits< Graph >::vertex_iterator vertex_iterator_t;    typedef typename graph_traits< Graph >::edge_descriptor edge_t;    typedef typename graph_traits< Graph >::edges_size_type e_size_t;    typedef typename graph_traits< Graph >::vertices_size_type v_size_t;    typedef typename std::vector< vertex_t > v_list_t;    typedef typename v_list_t::iterator v_list_iterator_t;    typedef iterator_property_map< typename std::vector< v_list_t >::iterator,        VertexIndexMap >        vertex_to_v_list_map_t;    typedef adjacency_list< vecS, vecS, undirectedS > small_graph_t;    detail::target_graph_t target_graph        = detail::tg_k_3_3; // unless we decide otherwise later    static small_graph_t K_5(detail::make_K_5< small_graph_t >());    static small_graph_t K_3_3(detail::make_K_3_3< small_graph_t >());    v_size_t n_vertices(num_vertices(g));    v_size_t max_num_edges(3 * n_vertices - 5);    std::vector< v_list_t > neighbors_vector(n_vertices);    vertex_to_v_list_map_t neighbors(neighbors_vector.begin(), vm);    e_size_t count = 0;    for (ForwardIterator itr = begin; itr != end; ++itr)    {        if (count++ > max_num_edges)            return false;        edge_t e(*itr);        vertex_t u(source(e, g));        vertex_t v(target(e, g));        neighbors[u].push_back(v);        neighbors[v].push_back(u);    }    for (v_size_t max_size = 2; max_size < 5; ++max_size)    {        vertex_iterator_t vi, vi_end;        for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)        {            vertex_t v(*vi);            // a hack to make sure we don't contract the middle edge of a path            // of four degree-3 vertices            if (max_size == 4 && neighbors[v].size() == 3)            {                if (neighbors[neighbors[v][0]].size()                        + neighbors[neighbors[v][1]].size()                        + neighbors[neighbors[v][2]].size()                    < 11 // so, it has two degree-3 neighbors                )                    continue;            }            while (neighbors[v].size() > 0 && neighbors[v].size() < max_size)            {                // Find one of v's neighbors u such that v and u                // have no neighbors in common. We'll look for such a                // neighbor with a naive cubic-time algorithm since the                // max size of any of the neighbor sets we'll consider                // merging is 3                bool neighbor_sets_intersect = false;                vertex_t min_u = graph_traits< Graph >::null_vertex();                vertex_t u;                v_list_iterator_t v_neighbor_end = neighbors[v].end();                for (v_list_iterator_t v_neighbor_itr = neighbors[v].begin();                     v_neighbor_itr != v_neighbor_end; ++v_neighbor_itr)                {                    neighbor_sets_intersect = false;                    u = *v_neighbor_itr;                    v_list_iterator_t u_neighbor_end = neighbors[u].end();                    for (v_list_iterator_t u_neighbor_itr                         = neighbors[u].begin();                         u_neighbor_itr != u_neighbor_end                         && !neighbor_sets_intersect;                         ++u_neighbor_itr)                    {                        for (v_list_iterator_t inner_v_neighbor_itr                             = neighbors[v].begin();                             inner_v_neighbor_itr != v_neighbor_end;                             ++inner_v_neighbor_itr)                        {                            if (*u_neighbor_itr == *inner_v_neighbor_itr)                            {                                neighbor_sets_intersect = true;                                break;                            }                        }                    }                    if (!neighbor_sets_intersect                        && (min_u == graph_traits< Graph >::null_vertex()                            || neighbors[u].size() < neighbors[min_u].size()))                    {                        min_u = u;                    }                }                if (min_u == graph_traits< Graph >::null_vertex())                    // Exited the loop without finding an appropriate neighbor                    // of v, so v must be a lost cause. Move on to other                    // vertices.                    break;                else                    u = min_u;                detail::contract_edge(neighbors, u, v);            } // end iteration over v's neighbors        } // end iteration through vertices v        if (max_size == 3)        {            // check to see whether we should go on to find a K_5            for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)                if (neighbors[*vi].size() == 4)                {                    target_graph = detail::tg_k_5;                    break;                }            if (target_graph == detail::tg_k_3_3)                break;        }    } // end iteration through max degree 2,3, and 4    // Now, there should only be 5 or 6 vertices with any neighbors. Find them.    v_list_t main_vertices;    vertex_iterator_t vi, vi_end;    for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)    {        if (!neighbors[*vi].empty())            main_vertices.push_back(*vi);    }    // create a graph isomorphic to the contracted graph to test    // against K_5 and K_3_3    small_graph_t contracted_graph(main_vertices.size());    std::map< vertex_t,        typename graph_traits< small_graph_t >::vertex_descriptor >        contracted_vertex_map;    typename v_list_t::iterator itr, itr_end;    itr_end = main_vertices.end();    typename graph_traits< small_graph_t >::vertex_iterator si        = vertices(contracted_graph).first;    for (itr = main_vertices.begin(); itr != itr_end; ++itr, ++si)    {        contracted_vertex_map[*itr] = *si;    }    typename v_list_t::iterator jtr, jtr_end;    for (itr = main_vertices.begin(); itr != itr_end; ++itr)    {        jtr_end = neighbors[*itr].end();        for (jtr = neighbors[*itr].begin(); jtr != jtr_end; ++jtr)        {            if (get(vm, *itr) < get(vm, *jtr))            {                add_edge(contracted_vertex_map[*itr],                    contracted_vertex_map[*jtr], contracted_graph);            }        }    }    if (target_graph == detail::tg_k_5)    {        return boost::isomorphism(K_5, contracted_graph);    }    else // target_graph == tg_k_3_3    {        return boost::isomorphism(K_3_3, contracted_graph);    }}template < typename Graph, typename ForwardIterator >bool is_kuratowski_subgraph(    const Graph& g, ForwardIterator begin, ForwardIterator end){    return is_kuratowski_subgraph(g, begin, end, get(vertex_index, g));}}#endif //__IS_KURATOWSKI_SUBGRAPH_HPP__
 |