提升最大连通分量的大小

问题描述

我知道如何计算 Boost 中连通分量的总数,但是有没有一种有效的方法可以使用 boost 的图形库来计算最大连通分量的大小。

解决方法

我认为最有效的方法是用自定义类型替换 component map

我创建了一个小的 WritePropertyMap 来做到这一点:

template <typename V>
struct Mapper {
    using Id          = int; // component id
    using Cardinality = int;

    using Map   = boost::container::flat_map<Id,Cardinality>;
    using Value = Map::value_type;
    Map& storage;

    friend void put(Mapper& m,V const& /*v*/,Id id) { m.storage[id] += 1; }

    Value largest() const {
        return not storage.empty()
            ? *max_element(begin(storage),end(storage),[](Value const& a,Value const& b) {
                       return a.second < b.second;
                   })
            : Value{};
    }
};

我们需要将我们的属性映射告诉 Boost:

template <typename V> struct boost::property_traits<Mapper<V>> {
    using category   = boost::writable_property_map_tag;
    using key_type   = V;
    using value_type = int;
};

注意

存储和属性映射之间的分离是因为属性映射是按值传递的 - 并且复制起来应该很便宜。

现在我们可以使用它,稍微调整一下 library example

Live On Coliru

Mapper<V>::Map result;
Mapper<V> mapper{result};
int num = connected_components(g,mapper);

auto [id,cardinality] = mapper.largest();
std::cout << "Largest component #" << id << " (out of " << num
          << " components) has " << cardinality << " vertices\n";

印刷品

Largest component #0 (out of 3 components) has 3 vertices

这符合预期的输出。

奖金

如果您有预期数量的组件,您可以使用 small_vector/static_vector 来优化存储,例如

using Value = std::pair<Id,Cardinality>;
using Map = boost::container::flat_map<
    Id,Cardinality,std::less<>,boost::container::small_vector<Value,10>>;

这样,除非您有超过 10 个组件,否则您永远不会看到映射器存储的动态分配。