我最近看到了一个名为4 Fours的逻辑/数学问题,你需要使用4个四和一系列运算符来创建等于0到N的所有整数的方程式。
你会如何编写一个优雅的算法来说出前100 ...
我开始创建基本计算,如4-4,4 + 4,4x4,4 / 4,4!,Sqrt 4,并使这些值成为整数。
然而,我意识到这将是一个强力方法测试组合,看看它们是否相等,0然后是1,然后是2,然后是3 ......等等。
然后我想到找到上述值的所有可能组合,检查结果是否小于100并填充数组然后对其进行排序......再次效率低下,因为它可能会发现1000多个数字超过100
任何有关如何处理此类问题的帮助都会有所帮助......不是实际的代码......但是如何思考这个问题
谢谢!
答案 0 :(得分:2)
这是一个有趣的问题。这里有几件不同的事情。一个问题是如何描述进入算术表达式的操作序列和操作数。使用括号来建立操作顺序非常混乱,因此我建议将表达式视为一堆操作和操作数,例如- 4 4
表示4-4,+ 4 * 4 4
表示(4 * 4)+ 4,* 4 + 4 4
表示(4 + 4)* 4等。它类似于HP计算器上的反向波兰表示法。然后你不必担心括号,当我们构建越来越大的表达式时,表达式的数据结构会有所帮助。
现在我们转向构建表达式的算法。在我看来,动态编程在这种情况下不起作用,因为(例如)构造一些0到100范围内的数字,你可能不得不暂时超出该范围。
我认为,将问题概念化的更好方法是在图表上作为广度优先搜索(BFS)。从技术上讲,图形将是无限的(所有正整数,或所有整数,或所有有理数,取决于你想要得到的精细程度),但在任何时候你只有图的有限部分。稀疏的图形数据结构是合适的。
图表上的每个节点(数字)都有一个与之关联的权重,到达该节点所需的最小数量4,以及实现该结果的表达式。最初,您将从节点(4)开始,其中数字1与之关联(需要一个4才能生成4)和简单表达式#34; 4"。您也可以使用重量为2(444)(重量为3)和(4444)重量为4(44)。
要构建更大的表达式,请将所有不同的操作应用于这些初始节点。例如,一元否定,阶乘,平方根;堆栈底部的* 4
等二进制运算乘以4,+ 4
,- 4
,/ 4
,^ 4
进行求幂,以及{{1操作的权重是该操作所需的4的数量;等等。一元操作将具有权重0,+ 44
将具有权重1,+ 4
将具有权重2,等等。您将操作的权重添加到其操作的节点的权重以获得新的权重,例如* 44
作用于节点(44),权重为2,表达式为#34; 44"将导致具有权重3和表达式#34; + 4 44"的新节点(48)。如果48的结果具有比48的现有结果更好的权重,则将该新节点替换为(48)。
在应用函数时,您必须使用某种意义。 factorial(4444)将是一个非常大的数字;为你的阶乘函数设置一个域是明智的,这会阻止结果变得太大或超出界限。与/ 4等功能相同;如果你不想处理分数,那么说4的非倍数超出/ 4的范围,并且在这种情况下不适用运算符。
得到的算法非常类似于Dijkstra的算法,用于计算图中的距离,但不完全相同。
答案 1 :(得分:1)
我认为这里的蛮力解决方案是唯一可行的方法
这背后的原因是每个号码都有不同的方式来获取它,而获得某个 <WrapPanel Width=200px />
可能与获取x
无关。
话虽如此,你可以在可能的情况下使用明显的动作,使蛮力解决方案更快一些。
例如,如果我使用&#34; 4&#34;三次(x+1
),显然可以达到16,24和80.持有100位数组并标记已达到的数字
答案 2 :(得分:1)
与子集求和问题类似,可以使用Dynamic Programming (DP)通过遵循递归公式来解决:
D(0,0) = true
D(x,0) = false x!=0
D(x,i) = D(x-4,i-1) OR D(x+4,i-1) OR D(x*4,i-1) OR D(x/4,i-1)
通过使用DP技术计算上述内容,很容易找出使用这些数据可以生成哪些数字,并且通过退回解决方案,您可以了解每个数字是如何构建的。
此方法的优点(使用DP实现时)是您不会多次重新计算多个值。我不确定它对4 4 4实际上是否有效,但我相信理论上它可能是对这个问题的一个较少限制泛化的重大改进。
答案 3 :(得分:1)
这个答案只是Amit的延伸。 基本上,您的操作是:
对于1..4中的每个n
,计算Expressions(n)
- (表达式,值)对的列表,如下所示:
(对于固定的n
,只在列表中存储1表达式,其中计算结果为任何给定值)
n
4s(即4,44,444,4444)的串联初始化列表i
的{{1}}以及每个允许的二元运算符n-1
,添加op
所在的表达式(和值)e1 op e2
{ {1}}和e1
位于Expressions(i)
示例一元运算符为e2
,Expressions(n-i)
,!
等。示例二元运算符为Sqrt
等。您可以轻松地将此方法扩展到具有更多参数的运算符允许的。
对于任何给定的-
,你可以做一些更聪明的事情。在+-*/^
完成所有n
之前,简单方法(如上所述)不会开始计算Expressions(i)
。这要求我们知道何时停止。另一种方法是为每个Expressions(j)
构建一个特定最大长度的表达式,然后如果需要(因为您没有找到某些值),请在外部循环中扩展最大长度。