2

我有一个数学和编程问题。

对于给定的一组字符{1,2,3,4,5,6,7,8,9,+,-,*,/}。然后通过使用字符集在数组中随机生成10(或者说)字符,即. 之后,我需要通过使用这个字符数组加上 1 个字符“=”来找到方程的所有可能性。N[1,+,1,∗,3,5,7,8,1]

因此,在这种情况下,[1,+,1,∗,3,5,7,8,1]它会像以下等式:1*1=1, 3+5=8, 7+1=8, 15=8+7, 15+3=18(可能更多)

可形成多位运算,即15+3=18

所以我的问题是我正在尝试使用一个程序来生成所有方程。你们能给我一些想法,什么样的算法可以做到这一点?或者有什么方法可以做到吗?

我目前的做法:

我的方法不够快。所以想法是,最小方程需要 3 个数字和 1 个运算符。和

  1. 我从生成的数组中随机挑选 4 个成员开始。如果这 4 个成员有一个操作员,
  2. 然后我会添加'='
  3. 形成所有可能的订单。例如 1,1,2,+ ,我将有 112+=, 121+= ,1=12+ .... 循环遍历所有这些。和
  4. 然后增加到 5 个成员并循环遍历它...
  5. 这样做直到生成数组的长度
4

2 回答 2

4

正如评论中已经提到的,这似乎是 NP 完全的,因此是指数级的,因此需要长时间,但这仍然是我要做的:

对于输入的每个可能的子集 A,请执行以下操作:

生成 A 的所有排列。

所以每个排列都对应一个方程(或者那个像方程但没有=符号的东西)。

现在请注意,会有很多无效的“方程式”。之类的东西1**1。您需要在进行时忽略所有这些。几乎任何以一个运算符或连续 2 个运算符开始或结束的东西都是无效的(或者可能不是,1*-2-2+1( 1--1?) 是有效的(1++1+1+2?),但无论如何,我相信你能弄清楚)。

对于每个有效的排列,将评估它得到的数字添加到一个集合(嗯,一个(多)数字到方程的映射)。

当从输入中删除 A 时(导致另一个生成的集合),对剩余项目的所有排列执行相同的操作。

现在出现在两组中的所有数字都是有效的方程。请注意(因为不想解释)您将对所有具有相同编号的方程执行类似CROSS JOIN的过程。

我们是否只生成了每个集合两次,一次在左侧,一次在右侧?哎呀。好的,这是一个修复:“为包含该元素的输入的每个可能的子集 A 选择任何元素......”。

需要考虑的事情 - 分离运营商

优点:可能快很多(不太确定,甚至可能更慢)
缺点:复杂很多

预处理输入,删除所有运算符,然后简单地计算每个运算符。

执行与上面完全相同的操作,但是对于每个排列,还生成运算符可以去哪里的所有排列。如果做得对,您应该能够完全避免无效的方程式。

并且还有多个集合可以放入数字(因此您将有 2 组集合),一个用于允许的每种类型的运算符的每个可能数量,然后您将与另一组进行比较(在另一组集合中) ) 使得所有运算符的数量都被使用。

用一个例子来解释:

输入:[1,*,1,3,5,7,8,+,+,1]

不带运算符的输入:[1,1,3,5,7,8,1]

运营商:

Operator  Count
+         2
*         1

一个示例子集:[1,7,8,1]
它的补充:[1,3,5]

现在我们将有 2x 6 个集合,一个用于两个集合的可能运算符的每种组合:

            ++*      ++      +*      +      *      NONE
Subset      +1*1+78  11+7+8  1*1+78  117+8  1*178  1178
Complement  +3*5+1   3+5+1   3*5+1   35+1   3*51   351

以上只是示例,每个集合显然不止1个方程,您需要考虑运算符可以去的任何地方,例如,考虑++*

+1+1*78
+1+17*8
+11+7*8
1+1+7*8
1*1+7+8
1+1*7+8
etc.

而且我只考虑了1178示例和351补码的排列,但所有排列都需要添加(即 1187、1718、1781、...和 ​​315、513、531、...)。

将所有这些都添加到集合后,您可以按如下方式匹配集合,因此我们在等式中使用所有运算符:

Subset      Complement
++*    with NONE
++     with *
+*     with +
+      with +*
*      with ++
NONE   with ++*

为了更好地了解会发生什么,并假设我们的数学真的很差,我们可以说:(取自上面的网格)

+1*1+78 = 351
11+7+8 = 3*51
1*1+78 = 35+1
etc.

现在,您将使用它计算的值来匹配方程(使用排序集将允许您在线性时间内同时逐步完成这两个)。所以,假设子集的方程 A 和 B 都计算为 79,补码的方程 C 和 D 也计算为 79。现在你将它们匹配如下:(这就是我所说的 CROSS JOIN)

A = C
A = D
B = C
B = D

还有(如果你想要这些):

C = A
C = B
D = A
D = B

我希望能澄清它。

于 2013-05-18T21:51:36.093 回答
0

作为使用上述示例集的解决方案的原始破解,一种算法将是直接找到所选数字、运算符和 = 的所有组合并进行测试,例如

  • 所有变体中的所有 9 加上 =(10 个字符)。数量将是10×9×8×7×6×5×4×3×2×1 = 10! = 3,628,800变化。
  • 然后是所有变体中的 8 加上 =(9 个字符)。 10×9×8×7×6×5×4×3×2 = 10!÷1!.
  • 然后是所有变体中的 7 加上 =(8 个字符)。 10×9×8×7×6×5×4×3 = 10!÷2!.
  • 等等,直到所有变体中的 4 加上 =(3 个数字和 2 个运算符 = 5 个字符)。 10×9×8×7×6 = 10!÷5!.

那么这个等式就是(n+1)!÷0! + (n+1)!÷1! + ... + (n+1)!÷(n-4)!

  • 哪里n是生成的数字和运算符的数量减去 =。

在您的示例中,将有9,858,240 个潜在方程。值得注意的是,会有无效的方程式,其中 = 位于末尾,= 和运算符一起等。所以我很肯定可以存在更好的方程式。

  • 排除两端的 = 将减少 1,971,648
于 2013-05-24T12:39:36.827 回答