根据集合中的数字计算目标数量

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)

我试图用伪代码表示算法,但到目前为止还没有走得太远.我认为图表是要走的路,但肯定会感谢你的帮助.谢谢.

IVl*_*lad 5

好吧,你没有提到效率,所以我要发布一个非常强力的解决方案,让你优化它,如果你想.由于您可以使用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)


pol*_*nts 5

这并不是最快的解决方案,而是一种有益的解决方案.

  • 它以后缀表示法递归地生成所有方程
  • 它还提供从后缀到中缀表示法的翻译
  • 没有进行实际的算术计算,因此您必须自己实现
    • 除零之前要小心

有4个操作数,4个可能的运算符,它生成所有7680 = 5*4!*4 ^ 3可能的表达.

  • 5是加泰罗尼亚语(3).加泰罗尼亚语(N)是对N + 1个操作数进行paranthesize的方法的数量.
  • 4!因为4个操作数是可以置换的
  • 4 ^ 3因为3个运营商各有4个选择

这肯定不能很好地扩展,因为N个操作数的表达式的数量是[1,8,192,7680,430080,30965760,2724986880,...].

通常,如果您有n+1操作数,并且必须插入nk可能性中选择的运算符,则(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)


Der*_*k E 5

在考虑如何解决问题之前(比如图表),只关注问题真的很有帮助.如果你发现自己陷入困境并且似乎无法想出任何伪代码,那么很可能会有一些东西阻碍你; 尚未解决的其他一些问题或疑虑.在这种情况下,一个示例"粘性"问题可能是"这个问题究竟是什么递归?"

在阅读下一段之前,请先尝试回答这个问题.如果你知道什么是递归的问题,那么编写一个递归方法来解决它可能并不是很困难.

您想知道某个使用一组数字的表达式(每个数字只使用一次)是否为您提供目标值.有四个二进制运算,每个运算都有一个运算.所以,换句话说,你想知道第一个用其他数字的表达式操作的数字是否能给你目标.好吧,换句话说,你想知道'其他'数字的某些表达是否是[...].如果没有,那么使用带有第一个数字的第一个操作并不能真正满足您的需求,所以请尝试其他操作.如果它们不起作用,那么也许它本身并不意味着.

编辑:我认为这是因为没有括号的四个运算符的中缀表达式,因为对原始问题的评论说为了示例而添加了括号(为了清楚起见?)并且没有明确说明括号的使用.


tza*_*man 3

一般来说,当您需要递归地执行某些操作时,从“底部”开始并向上思考会有所帮助。考虑:您有一组nS个数字和一组四个操作。让我们调用在集合上运行的递归函数{a,b,c,...}{+,-,*,/}F(S)

  • 如果n为 1,则F(S)就是该数字。
  • 如果n为 2,F(S)则可以是八项:
    • S从(2 个选择)中选择您左侧的号码
    • 然后选择要应用的操作(4 个选项)
    • 你右边的数字将是集合中剩下的数字
  • 现在,您可以从n中归纳出 =2 的情况进行概括:
    • x从中选择一个数字S作为左侧操作数(n个选择)
    • 选择要应用的操作
    • 你右手边的号码是F(S-x)

我会让你把它从这里拿走。:)

编辑:马克提出了有效的批评;上述方法并不能得到绝对的一切。要解决这个问题,您需要以稍微不同的方式来思考:

  • 在每一步中,您首先选择一个操作(4 个选项),然后
  • 划分 S为左右手操作数的两组,
  • 并递归地应用于F两个分区

不过,将一个集合的所有划分分成两部分本身并不简单。