【问题标题】:C++ algorithm for 2 lines with same length2行相同长度的C++算法
【发布时间】:2016-11-21 02:34:33
【问题描述】:

我找不到解决此类问题的好方法: 我们有 5

例如: 5段长度:1 5 2 3 4 正确的解法是:第 1 根柱子 2+5=7,第 2 根柱子 3+4=7。

你会怎么处理?

【问题讨论】:

  • 貌似是一个竞赛题
  • 这不是在这里提问的正确方式。但提示:对于每个数字,将其与所有其余的单独相加。你会得到一个矩阵。在整个矩阵中找到最大值。检查你是否在其他地方有建立的最大值,如果没有,取整个矩阵的 2nd 最大值并重新检查它;直到找到“匹配”
  • 老实说,这听起来像是重复应用子集和问题。可能是 NP 完全的。
  • 在 1 2 3 4 5 6 7 8 9 的情况下,您可以省略 1 并使用 2 3 8 9 和 4 5 6 7 达到 22。这很容易找到,因为数字是连续。
  • en.wikipedia.org/wiki/Partition_problem 听起来像是您想要做的。维基百科文章有几个算法。 quora.com/… 也有一些关于子集总和的额外答案。

标签: c++ algorithm


【解决方案1】:

Wikipedia 上有一篇关于 the Partition Problem in Computer Science 的文章,其标题听起来像是您想要做的。

在计算机科学中,分区问题(或数字分区1) 是决定一个给定的多重集 S 是否为正 整数可以划分为两个子集 S1 和 S2,使得 S1 中的数字之和等于 S2 中的数字之和。虽然 划分问题是NP完全的,存在一个伪多项式 时间动态规划解决方案,并且有启发式解决方案 在许多情况下,无论是最优的还是近似的。为了 因此,它被称为“最简单的 NP-hard 问题”。

参考了几种不同的算法来提供解决方案。

另见下文。

Is partitioning an array into halves with equal sums P or NP?

3-PARTITION problem

custom partition problem

C++ Elegant solution to partition problem

【讨论】:

    【解决方案2】:

    这是一些奇怪的代码,但它的工作。 (请注意,此代码未应用任何优化,可能运行缓慢, 最适合小型集合 - x! 复杂性)

    template<template<typename...> class Set = std::vector,
             template<typename...> class Pair = std::pair,
             template<typename...> class Cont,
             typename... Ts>
    inline Set<Cont<Pair<typename Cont<Ts...>::value_type, size_t>>> all_subsets(const Cont<Ts...>& cont)
    {
        Set<Cont<Pair<typename Cont<Ts...>::value_type, size_t>>> all_subsets;
        Cont<Pair<typename Cont<Ts...>::value_type, size_t>> empty;
        all_subsets.push_back(empty);
    
        for(auto it1 = cont.begin(); it1 != cont.end(); ++it1)
        {
            Set<Cont<Pair<typename Cont<Ts...>::value_type, size_t>>> temp_subset = all_subsets;
            for(auto& it2 : temp_subset)
                it2.push_back({*it1, std::distance(cont.begin(), it1)});
            for(const auto& it2 : temp_subset)
                all_subsets.push_back(it2);
        }
        return all_subsets;
    }
    
    template<template<typename...> class Cont,
             typename... Ts>
    inline bool intersects_by_second(const Cont<Ts...>& first,  const Cont<Ts...>& second)
    {
        for(auto it1 : first)
            for(auto it2 : second)
                if(it1 == it2)
                    return true;
        return false;
    }
    
    template<template<typename...> class Cont,
             typename... Ts>
    inline Cont<typename Cont<Ts...>::value_type::first_type> make_vector_of_firsts(const Cont<Ts...> cont)
    {
        Cont<typename Cont<Ts...>::value_type::first_type> result;
        for(const auto& it : cont)
            result.push_back(it.first);
        return result;
    }
    
    template<template<typename...> class Cont,
             typename... Ts>
    inline Cont<typename Cont<Ts...>::value_type::second_type> make_vector_of_seconds(const Cont<Ts...> cont)
    {
        Cont<typename Cont<Ts...>::value_type::second_type> result;
        for(const auto& it : cont)
            result.push_back(it.second);
        return result;
    }
    
    template<template<typename...> class Bag = std::vector,
             template<typename...> class Pair = std::pair,
             template<typename...> class Cont,
             typename... Ts>
    inline Bag<Pair<Cont<Ts...>, Cont<Ts...>>> full_sum_partition(const Cont<Ts...>& cont)
    {
        auto subsets = all_subsets(cont);
    
        Bag<Pair<Cont<Ts...>, Cont<Ts...>>> result;
    
        for(auto it1 : subsets)
            for(auto it2 : subsets)
            {
                auto it1_firsts = make_vector_of_firsts(it1);
                auto it2_firsts = make_vector_of_firsts(it2);
                if(std::accumulate(it1_firsts.begin(), it1_firsts.end(), 0)
                   ==
                   std::accumulate(it2_firsts.begin(), it2_firsts.end(), 0))
                {
                    if(intersects_by_second(it1, it2)
                       ||
                       it1.size() != it2.size())
                        continue;
                    result.push_back(Pair<Cont<Ts...>, Cont<Ts...>>
                                     (it1_firsts,
                                      it2_firsts));
                }
            }
        return result;
    }
    
    
    
    int main()
    {
        std::vector<int> vec{1,4,9,16,25,36,49,64};
        auto result = full_sum_partition(vec);
    
        for(const auto& x : result)
            std::cout << x << " with sum " << std::accumulate(x.first.begin(),
                                                              x.first.end(),
                                                              0) << std::endl;
    }
    

    输出:

    ([], []) with sum 0
    ([1, 25, 36], [4, 9, 49]) with sum 62
    ([16, 25, 36], [4, 9, 64]) with sum 77
    ([4, 9, 49], [1, 25, 36]) with sum 62
    ([16, 49], [1, 64]) with sum 65
    ([4, 36, 49], [9, 16, 64]) with sum 89
    ([1, 16, 36, 49], [4, 9, 25, 64]) with sum 102
    ([1, 64], [16, 49]) with sum 65
    ([4, 9, 64], [16, 25, 36]) with sum 77
    ([9, 16, 64], [4, 36, 49]) with sum 89
    ([4, 9, 25, 64], [1, 16, 36, 49]) with sum 102
    Press <RETURN> to close this window...
    

    还请注意,我为各种容器重载了运算符

    for(const auto& x : result)
    {
        size_t i=0;
        std::cout << "([";
        for(i=0; i< x.first.size(); ++i)
            std::cout << x.first[i] << "],"[(i<x.first.size()-1)];
        if(i==0)
            std::cout << ']';
        std::cout << ",[";
        for(i=0; i< x.second.size(); ++i)
            std::cout << x.second[i] << "],"[(i<x.first.size()-1)];
        if(i==0)
            std::cout << ']';
        std::cout << ')'
                  << " with sum " << std::accumulate(x.first.begin(),
                                                    x.first.end(),
                                                    0) << std::endl;
    }
    

    【讨论】:

    • 因子复杂度?这将比 2^n 更糟。输入 50,OP 可能会看到,宇宙将在计算完成之前结束。
    • @AndyG 是的,但我不需要理论知识来实现​​任何更快的版本。我知道比 x^{2,3,4...} 更复杂的一切都非常糟糕(就像这段代码:))
    • 这很公平。不过,作为参考,一个蛮力解决方案计算所有可能的组合,然后迭代直到找到两个相同且最大的只有 O(2^N),它小于 N!。我实际上并没有解析你的代码,所以我不知道这是否是你真正的复杂性。我建议您研究一下 Karps 21 NP-Complete 问题,如果您想了解更多信息,也许可以深入研究如何通过约简证明问题是 NP-Complete。
    猜你喜欢
    • 2023-01-07
    • 1970-01-01
    • 2011-03-23
    • 1970-01-01
    • 2017-11-18
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多