【问题标题】:How many ways to get 21 given a list of numbers? How to get all posible combinations of numbers?给定一个数字列表,有多少种方法可以得到 21?如何获得所有可能的数字组合?
【发布时间】:2014-03-23 14:01:51
【问题描述】:

好的,所以我必须解决这个问题,其中用户给出一个包含 7 或 k 数字的列表,我必须告诉有多少种方法可以使用和和减法获得 21n这些数字中。 我必须使用所有数字。
例如,用户给出数字:(1 3 4 5 9 1 7)。我可以将所有这些数字放入长度为 7 的数组中,并计算我使用这些数字的总和和/或子数得到 21 的次数: 1 +/- 3 +/- 4 +/- 5 +/- 9 +/- 1 +/- 7

这个问题的代码已经写好了:

count-twenty-one(int* dig, int n, int pos, int sum, int res) {
   if (pos==n) {
       if(sum==21)
         return res++;
   }
   count-twenty-one(dig, n, pos+1, sum+dig[pos], res)
   count-twenty-one(dig, n, pos+1, sum-dig[pos], res)
}

正如您所看到的,这使得 DFS(深度优先搜索)可以找到有多少种方法可以得到 21。现在,实际的问题是如何知道有多少种方法可以得到 21使用 给定数字的组合,我必须再次使用它们。例如,用户给出数字:

(0 0 0 0 2 1 0)。我无法使用 0 + 0 - 0 + 0 + 2 + 1 + 0 得到 21。但是如果我将 2 和 1 附加并与另一个 0 相加/减去,我可以得到 21。 0 + 0 + 0 - 0 + 21 -0 = 21 假设用户现在给出 (2 3 9 8 5 0 7)。有了这个,我可以得到像23 98 5 7 这样的数字,并尝试看看有多少种方法可以获得所需的数字。但话又说回来,我可以拥有239 8 507

所以我想主要问题是从 (1 到 k) 中获取所有可能的数字组合-K 是数字列表的长度-然后在所有这些中使用 count-twenty-one。我该怎么做呢?我正在使用 C++ 和数组。

编辑

这个问题可以通过获取给定数组的所有可能分区,然后将所有这些分区放入count-twenty-one 来解决。有什么想法吗?

编辑 2: 这些数字是“有序”的,这意味着 (2 3 9 8 5 0 7) 我不能形成像 705 8 93 2 这样的组合

【问题讨论】:

  • 您的问题混合了两个不同的问题。第一个问题是想出一个比蛮力方法更好的合适算法(即尝试所有组合)。这与 C++ 完全无关。第二个问题是用 C++ 表达这个算法。对于第二个问题,最重要的是要正确:not 使用数组。使用std::vector
  • 我仍然不明白为什么不使用数组,它们还不错。无论如何,整个问题归结为获取给定集合的所有分区,然后使用这些分区查看是否可以使用给定分区获得所需的数字(使用 + 和 - 操作)。 :)
  • 数组太糟糕了。请查看 C++ 常见问题解答:parashift.com/c++-faq/arrays-are-evil.html
  • 好的,现在开始使用向量。 :) 这真的让事情变得更容易,我感谢你的帮助。但是关于如何解决这个问题的任何想法?
  • 不客气。对你的问题的算法部分没有任何想法,真的,或者更确切地说,我什至没有考虑太多。我的核心能力是 C++,所以我想我会把算法的东西留给更专业的人:)

标签: c++ arrays numbers combinations


【解决方案1】:

对于蛮力方法,以下可能会有所帮助:https://ideone.com/jAVRDk

void print(const std::vector<int>& digits,
           const std::vector<int>& seps,
           const std::vector<std::string>& s) {
    std::cout << digits[0];
    for (std::size_t i = 0; i != seps.size(); ++i) {
        std::cout << s[seps[i]] << digits[i + 1] ;
    }
    std::cout << std::endl;
}

bool next(std::vector<int>& seps)
{
    for (auto it = seps.rbegin(); it != seps.rend(); ++it) {
        if (++*it == 3) {
            *it = 0;
        } else {
            return true;
        }
    }
    return false;
}

void foo(std::vector<int> digits)
{
    const std::vector<std::string> s = {"", " + ", " - "};
    std::sort(digits.begin(), digits.end());

    do {
        std::vector<int> seps(digits.size() - 1, 0);

        do {
            print(digits, seps, s);
        } while (next(seps));
    } while (std::next_permutation(digits.begin(), digits.end()));

}

【讨论】:

  • 这有效,但不能同时有效。首先它需要 C++11,我必须让 Eclipse 和所有新的学校东西工作。但是,它需要每个数字并形成许多组合,例如0 1 2 形成2 1 0,这对我的需要无效(我知道,我的错!)
  • 使用foo({3,1,2,3}) 我得到1233 作为第一行,然后它开始按原样打印它,但我仍然认为它应该是3 1 2 3。这只会产生拥有分区的错觉(打印)。我实际上需要分区。感谢您的帮助。
  • @DavidMerinos:为什么需要“让 Eclipse 工作”,以及“所有这些新学校的东西”到底是什么?您可以在没有 Eclipse 的情况下完美地使用 GCC 和 MSVC,两者都可以免费下载(MS 提供包含完整编译器的 Visual Studio 的“Express Edition”),并且两者都可以在命令行上使用而无需任何 IDE。
  • @DavidMerinos:另外,我可以在这段代码中发现的 C++11 特性很容易被替换:foos 的初始化有四个 push_back()s,auto std::vector&lt;int&gt;::iterator.
  • @ChristianHackl 让我们不要丢失线程。我已经让 Eclipse 使用 C++11。我正在使用向量,我可以使用 auto 等等。我真的很感谢你的帮助。问题总结为获取向量的所有可能分区。我不知道该怎么做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-09
  • 2021-05-10
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
相关资源
最近更新 更多