微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C ++-如何遍历数组的所有组合以进行暴力破解

如何解决C ++-如何遍历数组的所有组合以进行暴力破解

我有一个练习,查找所有可能的1-9之和,总计为100,规则是每个数字必须使用一次并按顺序使用,允许的运算符为+/-并将数字加在一起例如。 1 + 2 + 3-4 + 5 + 6 + 78 + 9 = 100

我已经写出了计算逻辑的方法我有9个元素组成的数组,这些元素代表可以放置运算符的所有位置,其中1个为+,2个为-,以及3个将数字加在一起。 上例中的运算符字符串为{1,1,2,3,1}。

所以我真正的问题是如何遍历此运算符数组并生成每个可能的数字组合。

所以我开始 {1,1}

像这样一直进行到数组全为3s

111111111
111111112
111111113
111111121
111111122
111111123
111111131

我去年左右为此编写了一个函数,但是它使用了很多if else语句,使该函数不灵活,我想就此的正确过程提出建议,因为我想改善编码

解决方法

OP很公平地说,问题在于功课

我进行一次练习,查找所有1-9的可能总和,总计100

因此,我没有提供此练习的完整解决方案,但要实现此目的,无需过多添加。

给出了九个参数(数字1…9),它们是二进制运算符的参数。

二进制运算符需要一个左右参数。因此,我总结出有8个位置可以选择二元运算符。

对于+-来说很容易,但是添加数字又如何呢?

这是我称为“连接”的操作。实际上,很容易将“连接”表示为简单的算术表达式:

lr: 10 * l + r

解决“串联”问题后,这不再那么复杂了。

我的第一个想法是使用像函子或函数指针之类的东西,但是没有它就很难解决。

为此,我定义了一个操作枚举:

enum Op { Add,Sub,Cat,NOps};

compute()函数用于这些操作:

int compute(Op op,int l,int r)
{
  switch (op) {
    case Add: return l + r;
    case Sub: return l - r;
    case Cat: return l * 10 + r;
  }
  // ...unreachable for the humans eyes but not for the compiler...
  assert(false); return 0;
}

下一个拼图是一个为完整方程式计算结果的函数。 该方程式由N个自变量(数字)和N-1个运算符定义。

在执行此操作时,我意识到“串联”必须具有更高的优先级。否则,计算功能将无法正常工作。

示例:

12 + 23 = 35 

如果不考虑“串联”的更高优先级,则会导致:

12 + 23 = ((12) + 2)3 = (14)3 = 143

对于此问题的简单解决方案,compute函数应运行两次:

  1. 解决所有串联
  2. 解决所有其他操作。
int compute(std::vector<int> args,std::vector<Op> &ops)
{
  assert(args.size() == ops.size() + 1);
  // perform cat()
  std::vector<int> args2;
  args2.push_back(args[0]);
  for (size_t i = 0,n = ops.size(); i < n; ++i) {
    if (ops[i] == Cat) {
      int l = args2.back(); args2.pop_back();
      args2.push_back(compute(Cat,l,args[i + 1]));
    } else args2.push_back(args[i + 1]);
  }
  // perform add() and sub()
  int result = args2[0];
  for (size_t i = 0,j = 1,n = ops.size(); i < n; ++i) {
    const Op op = ops[i];
    if (op != Cat) result = compute(op,result,args2[j++]);
  }
  return result;
}

最后丢失的部分是std::vector<Op> &ops中类似Odometer的值的迭代。最简单的方法(尽管不是最优雅的方法)是分别嵌套for循环。

所以,我们在这里:

#include <cassert>
#include <iostream>
#include <vector>

enum Op { Add,NOps};

int compute(Op op,int r)
{
  switch (op) {
    case Add: return l + r;
    case Sub: return l - r;
    case Cat: return l * 10 + r;
  }
  // ...unreachable for the humans eyes but not for the compiler...
  assert(false); return 0;
}

/* Attention!
 * cat() must have higher precedence then add() and sub()
 */

int compute(std::vector<int> args,args2[j++]);
  }
  return result;
}

const char* toString(Op op)
{
  static const char* texts[] = { " + "," - ","" };
  return texts[op];
}

int main()
{
  std::vector<int> args = { 1,2,3,4 };
  std::vector<Op> ops(args.size() - 1);
  for (int op2 = 0; op2 < NOps; ++op2) {
    ops[2] = (Op)op2;
    for (int op1 = 0; op1 < NOps; ++op1) {
      ops[1] = (Op)op1;
      for (int op0 = 0; op0 < NOps; ++op0) {
        ops[0] = (Op)op0;
        // print equation
        std::cout << args[0];
        for (size_t i = 0,n = ops.size(); i < n; ++i) {
          std::cout << toString(ops[i]) << args[i + 1];
        }
        std::cout << " = " << compute(args,ops) << '\n';
      }
    }
  }
}

输出:

1 + 2 + 3 + 4 = 10
1 - 2 + 3 + 4 = 6
12 + 3 + 4 = 19
1 + 2 - 3 + 4 = 4
1 - 2 - 3 + 4 = 0
12 - 3 + 4 = 13
1 + 23 + 4 = 28
1 - 23 + 4 = -18
123 + 4 = 127
1 + 2 + 3 - 4 = 2
1 - 2 + 3 - 4 = -2
12 + 3 - 4 = 11
1 + 2 - 3 - 4 = -4
1 - 2 - 3 - 4 = -8
12 - 3 - 4 = 5
1 + 23 - 4 = 20
1 - 23 - 4 = -26
123 - 4 = 119
1 + 2 + 34 = 37
1 - 2 + 34 = 33
12 + 34 = 46
1 + 2 - 34 = -31
1 - 2 - 34 = -35
12 - 34 = -22
1 + 234 = 235
1 - 234 = -233
1234 = 1234

Live Demo on coliru

注意:

我只用了4位而不是9位数字,因为我认为这足以说明原理,并且应该易于通过OP进行扩展(以及将计算结果的检验添加为可接受或不可接受的)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。