【问题标题】:greedy algorithm for set cover c++集覆盖C++的贪心算法
【发布时间】:2015-01-05 15:30:53
【问题描述】:

Minimum Set Cover 是一个你必须找到覆盖每个元素所需的最小集合数的问题。 例如,假设我们有一组 X=array(1,2,3,4,5,6) 和另外 5 个集合 S,其中

S[1] = array(1, 4)   
S[2] = array(2, 5)   
S[3] = array(3, 6)  
S[4] = array(1, 2, 3)   
S[5] = array(4, 5, 6) 

问题是要找到覆盖 X 的每个元素的 S 的最小集合数。显然,在我们的例子中,最小集合覆盖将是 S[4]S[5],因为它们覆盖了所有元素。 有谁知道如何在 C++ 中实现此代码。请注意,这是 NP 完全的,因此没有快速算法来解决它。任何 C++ 解决方案都将受到欢迎。 顺便说一句,这不是作业,我需要在Quine–McCluskey 项目中使用这个算法来生成解决方案的最后一部分。
提前致谢。

【问题讨论】:

  • 虽然不是功课,但这也不是代码编写服务。无论如何,贪心方法实现起来都很简单:将集合添加到结果,直到结果包含所有元素。您为什么不自己尝试一下,并在遇到具体问题时提出问题?
  • 你想知道什么?算法或一些 C++ 实现细节/提示?如果是后者,具体需要实现哪种算法?
  • 我只需要一个 c++ 代码来解决集合覆盖问题
  • @BartoszKP 我如何才能为 2 套组合做到这一点,这没关系,但对于超过 2 套,我怎样才能找到 4 套的所有 3 套组合.....
  • @Jack 我认为您不是在考虑贪心算法,而是在考虑枚举所有可能的解决方案并找到最佳解决方案。那是完全不同的。但这并没有改变这样一个事实,即这不是一个代码编写服务。如果您坚持枚举组合,那么我很惊讶您没有找到这个(例如!):stackoverflow.com/questions/12991758/…

标签: c++ algorithm np-hard


【解决方案1】:

因此,您处于一种状态,您可以使用 Quine & McCluskey 方法确定所有主要蕴涵项。然后,您创建了质蕴涵表并提取了基本质蕴涵项。您检查了行和列的优势端消除了多余的行和列。但后来你走到了尽头,留下了一个循环核心。

     Ac Bc Ab bC aB aC 
  3   X  X
  5         X  X
  7   X     X
  9               X  X
 11      X        X
 13            X     X

现在你想使用集合覆盖问题来找出所有最小必要质蕴涵项。

为此,您可以使用 Petrick 的方法。这是一种精确的方法,会给你一组最小的结果。实现相当简单。 10行代码:

using MintermSet = std::set<MinTermNumber>;
using Minterm = std::set< BooleanVariable>;
using MintermVector = std::vector<MinTermNumber>;

using MaxtermSet = std::set<MaxTermNumber>;
using ConjunctiveNormalForm = std::set<MaxtermSet>;

using ProductTerm = std::set<BooleanVariable>;
using ProductTermVector = std::vector<ProductTerm>;

// Disjunctive Normal Form
using DNF = std::set<ProductTerm>;
// Conjunctive Normal Form
using CNF = std::vector<DNF>;


class PetricksMethod
{
public:
    // Functors operator
    ProductTermVector operator()(const CNF& cnf);
protected:
};


#include "petrick.hpp"

#include <algorithm>

// Functor operator for applying Petricks methhod

ProductTermVector PetricksMethod::operator ()(const CNF& cnf)
{
    // We select an iterative approach. Start with the first Element of the CNF (which is a DNF)
    // And we sorte the result of each iterative operation again in this element
    DNF resultingDNF{ cnf[0] };
    // We will always start with the element 1 (not element 0) becuase in 0 is the initial value
    // or respectively the intermediate result
    for (CNF::size_type dnfInCnfIndex = 1; dnfInCnfIndex < cnf.size(); ++dnfInCnfIndex)
    {
        // Result of multipliyong out od the intermediate (initial) value with the current CNF Product term
        DNF intermediateCalculatedDNF;
        // Now go through all elements of the intermediate (initial) product term/DNF
        // For (1+2)(3+4)  this would be the (1+2) part
        for (const ProductTerm& productTermLeftSide : resultingDNF)
        {
            // Next we will iterate over all Minterms in the next DNF
            // For (1+2)(3+4)  this would be the (3+4) part
            for (const ProductTerm& productTermRightSide : cnf[dnfInCnfIndex])
            {
                ProductTerm productTerm{ productTermLeftSide }; // Resulting Product term is now 1
                // Add all elements from the right side
                productTerm.insert(productTermRightSide.begin(), productTermRightSide.end());   // Resulting Product term is now 1,2
                intermediateCalculatedDNF.insert(std::move(productTerm));  // Store this one
                // And continue to add more product terms. The stl::set will ensure the idempotence law and prevent memory waste
            }
        }
        // And now add all found terms to the result and continue with the next element of the right hand side
        // Please note: also here the set will prevent double terms
        resultingDNF = std::move(intermediateCalculatedDNF);
    }

    // Now we have the result (with 10 lines of code). The result contains all product terms in DNF
    // But for our prupose we are only interested in the minimum size terms
    // so, lets find the element with the minimu size (can be more than one)
    uint minLength{ narrow_cast<uint>(std::min_element(resultingDNF.begin(), resultingDNF.end(), [](const ProductTerm & left, const ProductTerm & right) noexcept {return left.size() < right.size(); })->size()) };
    // And from the big list of the DNF with all product terms, we copy all elements having the minimu size to the result. These are our best coverage sets
    ProductTermVector cheapestVector;
    // Copy result and return it to caller
    std::copy_if(resultingDNF.begin(), resultingDNF.end(), std::back_inserter(cheapestVector), [&minLength](const ProductTerm& pt) noexcept {return pt.size() == minLength; });
    return cheapestVector;
}

所有这些都是您可以在GitHub 上找到的软件的一部分。您还可以看到完全实现的 Quine & McCluskey 算法。

希望这会有所帮助。 . .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多