sa1*_*125 20 algorithm numbers graph-algorithm
我正在做一个问我这个问题的作业问题:
Tiven有限的一组数字,并且一个目标号码,发现如果集合可以用于使用基本的数学运算(ADD,SUB,MULT,格),并使用组中的每个数字来计算目标数量恰好一次(所以我需要耗尽这套).这必须通过递归来完成.
所以,例如,如果我有这个集合
{1, 2, 3, 4}
Run Code Online (Sandbox Code Playgroud)
和目标10,然后我可以通过使用
((3 * 4) - 2)/1 = 10.
Run Code Online (Sandbox Code Playgroud)
我试图用伪代码表示算法,但到目前为止还没有走得太远.我认为图表是要走的路,但肯定会感谢你的帮助.谢谢.
好吧,你没有提到效率,所以我要发布一个非常强力的解决方案,让你优化它,如果你想.由于您可以使用parantheses,因此使用反向波兰表示法很容易强制它:
首先,如果你的集合有n个数字,你必须使用n - 1个运算符.因此,您的解决方案将由{{您给定的集},{*,/,+, - }}中的2n - 1个符号序列给出.
st = a stack of length 2n - 1
n = numbers in your set
a = your set, to which you add *, /, +, -
v[i] = 1 if the NUMBER i has been used before, 0 otherwise
void go(int k)
{
if ( k > 2n - 1 )
{
// eval st as described on Wikipedia.
// Careful though, it might not be valid, so you'll have to check that it is
// if it evals to your target value great, you can build your target from the given numbers. Otherwise, go on.
return;
}
for ( each symbol x in a )
if ( x isn't a number or x is a number but v[x] isn't 1 )
{
st[k] = x;
if ( x is a number )
v[x] = 1;
go(k + 1);
}
}
Run Code Online (Sandbox Code Playgroud)
这并不是最快的解决方案,而是一种有益的解决方案.
有4个操作数,4个可能的运算符,它生成所有7680 = 5*4!*4 ^ 3可能的表达.
这肯定不能很好地扩展,因为N个操作数的表达式的数量是[1,8,192,7680,430080,30965760,2724986880,...].
通常,如果您有n+1操作数,并且必须插入n从k可能性中选择的运算符,则(2n)!/n! k^n可能存在等式.
祝好运!
import java.util.*;
public class Expressions {
static String operators = "+-/*";
static String translate(String postfix) {
Stack<String> expr = new Stack<String>();
Scanner sc = new Scanner(postfix);
while (sc.hasNext()) {
String t = sc.next();
if (operators.indexOf(t) == -1) {
expr.push(t);
} else {
expr.push("(" + expr.pop() + t + expr.pop() + ")");
}
}
return expr.pop();
}
static void brute(Integer[] numbers, int stackHeight, String eq) {
if (stackHeight >= 2) {
for (char op : operators.toCharArray()) {
brute(numbers, stackHeight - 1, eq + " " + op);
}
}
boolean allUsedUp = true;
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] != null) {
allUsedUp = false;
Integer n = numbers[i];
numbers[i] = null;
brute(numbers, stackHeight + 1, eq + " " + n);
numbers[i] = n;
}
}
if (allUsedUp && stackHeight == 1) {
System.out.println(eq + " === " + translate(eq));
}
}
static void expression(Integer... numbers) {
brute(numbers, 0, "");
}
public static void main(String args[]) {
expression(1, 2, 3, 4);
}
}
Run Code Online (Sandbox Code Playgroud)
在考虑如何解决问题之前(比如图表),只关注问题真的很有帮助.如果你发现自己陷入困境并且似乎无法想出任何伪代码,那么很可能会有一些东西阻碍你; 尚未解决的其他一些问题或疑虑.在这种情况下,一个示例"粘性"问题可能是"这个问题究竟是什么递归?"
在阅读下一段之前,请先尝试回答这个问题.如果你知道什么是递归的问题,那么编写一个递归方法来解决它可能并不是很困难.
您想知道某个使用一组数字的表达式(每个数字只使用一次)是否为您提供目标值.有四个二进制运算,每个运算都有一个逆运算.所以,换句话说,你想知道第一个用其他数字的表达式操作的数字是否能给你目标.好吧,换句话说,你想知道'其他'数字的某些表达是否是[...].如果没有,那么使用带有第一个数字的第一个操作并不能真正满足您的需求,所以请尝试其他操作.如果它们不起作用,那么也许它本身并不意味着.
编辑:我认为这是因为没有括号的四个运算符的中缀表达式,因为对原始问题的评论说为了示例而添加了括号(为了清楚起见?)并且没有明确说明括号的使用.
一般来说,当您需要递归地执行某些操作时,从“底部”开始并向上思考会有所帮助。考虑:您有一组nS个数字和一组四个操作。让我们调用在集合上运行的递归函数{a,b,c,...}{+,-,*,/}F(S)
F(S)就是该数字。F(S)则可以是八项:
S从(2 个选择)中选择您左侧的号码x从中选择一个数字S作为左侧操作数(n个选择)F(S-x)我会让你把它从这里拿走。:)
编辑:马克提出了有效的批评;上述方法并不能得到绝对的一切。要解决这个问题,您需要以稍微不同的方式来思考:
S为左右手操作数的两组,F两个分区不过,将一个集合的所有划分分成两部分本身并不简单。