ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c-查找四个10的所有表达式

2019-10-10 08:09:53  阅读:253  来源: 互联网

标签:c prolog


我遇到了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使其更具创造力,以使其生成其他形状的树.

编辑:添加其余解决方案

我发现an answer by @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个!

标签:c,prolog
来源: https://codeday.me/bug/20191010/1885313.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有