更新std::set,只保留最小的值

Update std::set to keep only the smallest values

本文关键字:保留 std set 更新      更新时间:2023-10-16

对于某些算法,我必须在n -元素整数集的所有排列上调用函数f范围从1到n。最后,我对产生最小f值的100种排列感兴趣。

我能想出的最好的解决方案是下面这个。但它有一个严重的缺点。当n增加时,fPerm会消耗大量的内存。

修剪fPerm的最佳解决方案是什么,以便它只保留迄今为止发现的最好的100个解决方案?

#include <vector>
#include <set>
#include <algorithm>
#include <numeric>
#include <boost/random.hpp>
boost::random::mt19937 rng;
// Actually, f is a very complex function, that I'm not posting here.
double f(const std::vector<int>& perm) {
    boost::random::uniform_real_distribution<> gen;
    return gen(rng);
}
typedef std::pair<std::vector<int>, double> TValue;
void main(int argc, int args) {
    auto comp = [](const TValue& v1, const TValue& v2) { return v1.second < v2.second; };
    std::set<TValue, decltype(comp) > fPerm(comp);
    int n = 7;
    std::vector<int> perm(n);
    std::iota(perm.begin(), perm.end(),1);
    do {
        fPerm.insert(TValue(perm, f(perm)));
    } while (std::next_permutation(perm.begin(), perm.end()));
    // Get first smallest 100 values, if there are such many.
    int m = 100 < fPerm.size() ? 100 : fPerm.size();
    auto iterEnd = fPerm.begin();
    std::advance(iterEnd, m);
    for (auto iter = fPerm.begin(); iter != iterEnd; iter++) {
        std::cout << iter->second << std::endl;
    }
}

我修改了上面的解决方案,通过实现一种trim函数来擦除集合中最大的元素。正如下面所指出的,std::priority_queue的使用可能更短。

#include <vector>
#include <set>
#include <algorithm>
#include <numeric>
#include <boost/random.hpp>
boost::random::mt19937 rng;
double f(const std::vector<int>& perm) {
    boost::random::uniform_real_distribution<> gen;
    return gen(rng);
}
typedef std::pair<std::vector<int>, double> TValue;
void main(int argc, int args) {
    auto comp = [](const TValue& v1, const TValue& v2) { return v1.second < v2.second; };
    std::set<TValue, decltype(comp) > fPerm(comp);
    int n = 7;
    std::vector<int> perm(7);
    std::iota(perm.begin(), perm.end(),1);
    do {
        fPerm.insert(TValue(perm, f(perm)));
        if (fPerm.size() > 100) {
            fPerm.erase(*fPerm.rbegin());
        }
    } while (std::next_permutation(perm.begin(), perm.end()));
    // Get first smallest 100 values, if there are such many.
    int m = 100 < fPerm.size() ? 100 : fPerm.size();
    auto iterEnd = fPerm.begin();
    std::advance(iterEnd, m);
    for (auto iter = fPerm.begin(); iter != iterEnd; iter++) {
        std::cout << iter->second << std::endl;
    }
}
相关文章: