找到四个 10 的所有表达式
Find all expressions of four 10s
我遇到了一个CS问题的挑战。
该问题包括递归查找形式((10+10(/(10+10((的哪些表达式产生一个数字。例如,((10+10(/(10+10(( 产生 1。使用运算符 +、-、*、/和 4 个数字 10 和所有括号组合来查找所有其他表达式,以强制执行运算顺序。
我被推荐给反向波兰表示法,但它依赖于后缀表示法,这不是解决这个问题所必需的。
我有一些伪代码是这样的。我知道使用递归是解决此问题的最简单方法。但不知道如何确保我得到所有组合。
build([10,10,10,10], Expression) :-
Operator
/
[10] [10,10,10]
Operator
/
[10] [10,10]
Operator
/
[10] [10]
这是我试图在Prolog中解决的问题,但C++也很好。
我有一个部分解决方案,我将在这里概述,希望它能让你动起来,你可以找到完整的解决方案。
您需要的第一个工具是能够进行一些表达式:
build_expr(X, Y, X+Y).
build_expr(X, Y, X*Y).
build_expr(X, Y, X-Y).
build_expr(X, Y, X/Y).
这定义了build_expr/3
,它接受两个变量或表达式并产生一个新的表达式。这就是我们将如何排列运算符。现在我们需要一种方法来处理列表,所以让我们定义一次对列表进行操作build_expr/2
:
% base case: we are down to two variables and call build_expr/3
build_expr([X,Y], Expr) :- build_expr(X, Y, Expr).
% inductive case: make the expression on the rest of the list and combine
% with the leading variable here
build_expr([X|Rest], Expr) :-
build_expr(Rest, Expr0),
build_expr(X, Expr0, Expr).
让我们得到一些解决方案,以便我们了解它正在做的事情:
3 ?- build_expr([10,10,10,10],X).
X = 10+(10+(10+10)) ;
X = 10*(10+(10+10)) ;
X = 10-(10+(10+10)) ;
X = 10/(10+(10+10)) ;
X = 10+10*(10+10) ;
X = 10*(10*(10+10)) ;
X = 10-10*(10+10) ;
X = 10/(10*(10+10)) ;
X = 10+(10-(10+10)) ;
X = 10*(10-(10+10)) ;
X = 10-(10-(10+10)) ;
X = 10/(10-(10+10)) ;
这对我来说看起来还不错。但就像我说的,我只是在生成右倾的树。你将不得不修改或替换build_expr/2
以产生其他形状,如果它们真的重要(我不相信它们很重要(。
现在,让我们通过捆绑评估来简化下一步:
build_eval(L, Value) :- build_expr(L, Expr), Value is Expr.
现在我们应该能够使用setof/3
找到所有独特的解决方案:
6 ?- setof(X, build_eval([10,10,10,10],X), Results).
ERROR: Arithmetic: evaluation error: `zero_divisor'
ERROR: In:
ERROR: [15] _582 is 10/(10* ...)
ERROR: [14] build_eval([10,10|...],_622) at /Users/dlyons/fourtens.pl:11
ERROR: [13] '$bags':findall_loop(_664,user:build_eval(...,_682),_668,[]) at /usr/local/Cellar/swi-prolog/7.6.4/libexec/lib/swipl-7.6.4/boot/bags.pl:97
ERROR: [12] setup_call_catcher_cleanup('$bags':'$new_findall_bag','$bags':findall_loop(_728,...,_732,[]),_710,'$bags':'$destroy_findall_bag') at /usr/local/Cellar/swi-prolog/7.6.4/libexec/lib/swipl-7.6.4/boot/init.pl:443
ERROR: [8] '$bags':setof(_770,user:build_eval(...,_786),_774) at /usr/local/Cellar/swi-prolog/7.6.4/libexec/lib/swipl-7.6.4/boot/bags.pl:240
ERROR: [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
ERROR: [13] '$bags':findall_loop(_664,user:build_eval(...,_682),_668,[]) aabort
% Execution Aborted
哎呀。除以零误差。没问题,让我们抓住它并在这些情况下失败:
9 ?- setof(X, catch(build_eval([10,10,10,10],X), E, fail), Results), writeln(Results).
[-990,-900,-190,-100,-80,-20,-1,-0.1111111111111111,
0,0.01,0.05,0.09090909090909091,0.3333333333333333,1.0,1,
5.0,9.5,9.9,10,10.1,10.5,20.0,20,40,100.0,100,
120,210,300,1010,1100,2000,10000]
我在那里稍微摆弄了一下格式,但我认为这是一个很好的解决方案,但我已经可以看到一个缺少的解决方案:(10+10(*(10+10(=400。因此,您必须在build_expr/2
上更具创造力,以使其产生其他形状的树。
编辑:添加其余解决方案
我通过@gusbro找到了一个答案,它提供了一种枚举树的方法。我无法让它与我在那里做的递归技巧一起工作(也许其他人会向我展示一个非常简单的技巧(,但我能够使他的答案适应你的问题,即:
build_tree([I1,I2|Items], Expr) :-
append([L0|LR], [R0|RR], [I1,I2|Items]),
build_tree([L0|LR], Left),
build_tree([R0|RR], Right),
build_expr(Left, Right, Expr).
build_tree([E], E).
为什么我使用[L0|LR]
和[R0|RR]
而不是LeftList
和RightList
之类的?这就是我将@gusbro的数值约束转换为列表长度约束并确保我在左侧和右侧列表中始终至少有一个元素的方式,因此我对build_tree/2
的递归调用将成功。
将build_expr/3
从上面简化为单个运算符,您可以看到这会产生您期望的所有各种风格:
?- build_tree([10,10,10,10],X).
X = 10+(10+(10+10)) ;
X = 10+(10+10+10) ;
X = 10+10+(10+10) ;
X = 10+(10+10)+10 ;
X = 10+10+10+10 ;
false.
将其切换回来,因为我们仍在使用前面示例中的build_expr/3
函数。我使用这个build_eval/2
谓词简化了评估:
build_eval(L, Value) :-
build_tree(L, Expr), catch(Value is Expr, _, fail).
最终解决方案如下所示:
?- setof(X, build_eval([10,10,10,10], X), Res), writeln(Res).
[-990,-900,-190,-100,-99,-90,-80,-20,-19,-10,-9.9,-9.5,-9,
-8,-1.1111111111111112,-1,-0.9,-0.1111111111111111,
0,0.01,0.05,0.09090909090909091,0.1111111111111111,
0.2,0.3333333333333333,0.9,0.9090909090909091,1.0,1,
1.1,1.1111111111111112,2,3,5.0,5,8,9,9.5,9.9,10,10.1,10.5,11,
12,19,20.0,20,21,40,80,90,99,100.0,100,101,110,120,190,
200,210,300,400,900,990,1010,1100,2000,10000]
哇,很多选择,确切地说是 68 个!
- 找到四个 10 的所有表达式
- 如何在 c++ 中存储具有值的四个参数的元组
- C++ 函数,用于查找数组中四个最小最大元素的总和不起作用
- 如何实现四个 i8 元素组的高效_mm256_madd_epi8点积
- 如何将无符号的 int 值解释为四个字母的单词?
- 如何让变量随机输出四个单词之一
- 如何校准相机焦距,平移和旋转给定四个点
- 这C++ unordered_map怎么有四个值?我以为这是一个键值对
- 我想将四个字节合并为一个数字以进行串行传输
- QT将MainWindow拆分为四个小部件
- 如何将文本文件的各个部分导入到四个不同的字符串
- Curl - 发送数百个请求,但一次只能发送四个 - 编程
- 连接四个C 下降功能无法正常工作
- 连接四个成功的组合检查适用于大多数情况,但不适用于某些情况
- 使用C randint生成四个数字
- 读取四个数据文件并使用函数将它们放入结构数组的最佳方法是什么
- 由四个C++声明符号组成的整个组的名称
- 使用 std::transform() 添加四个向量 c++
- 难以传递lower_bound第四个参数
- C 四个旋转不按预期工作