如何找到公式的所有可能解,例如 100*7-8*3+7? (10 只猫中有 8 只做倒计时求解器)
how to find all possible solutions to a formula, like 100*7-8*3+7? (8 Out of 10 Cats Does Countdown solver)
为了好玩,我决定编写一个简单的程序来解决 10 只猫中有 8 只猫会倒计时 number puzzle,link 是倒计时形式,但规则相同。所以我的程序简单地遍历了 AxBxCxDxExF 的所有可能组合,其中字母是数字,"x" 是 +、-、/ 和 *。这是它的代码:
private void combineRecursive( int step, int[] numbers, int[] operations, int combination[]){
if( step%2==0){//even steps are numbers
for( int i=0; i<numbers.length; i++){
combination[ step] = numbers[ i];
if(step==10){//last step, all 6 numbers and 5 operations are placed
int index = Solution.isSolutionCorrect( combination, targetSolution);
if( index>=0){
solutionQueue.addLast( new Solution( combination, index));
}
return;
}
combineRecursive( step+1, removeIndex( i, numbers), operations, combination);
}
}else{//odd steps are operations
for( int i=0; i<operations.length; i++){
combination[ step] = operations[ i];
combineRecursive( step+1, numbers, operations, combination);
}
}
}
这是我用来测试组合是否符合我的要求的方法。
public static int isSolutionCorrect( int[] combination, int targetSolution){
double result = combination[0];
//just a test
if( Arrays.equals( combination, new int[]{100,'*',7,'-',8,'*',3,'+',7,'+',50})){
System.out.println( "found");
}
for( int i=1; i<combination.length; i++){
if(i%2!=0){
switch( (char)combination[i]){
case '+': result+= combination[++i];break;
case '-': result-= combination[++i];break;
case '*': result*= combination[++i];break;
case '/': result/= combination[++i];break;
}
}
if( targetSolution==result){
return i;
}
}
return targetSolution==result?0:-1;
}
所以在上一集中我发现我的代码有问题。这是其中一个难题的解决方案。
(10*7)-(8*(3+7))
我注意到我确实找到了这个组合“10*7-8*3+7”(两次),但是因为我通过从左到右的操作来检查解决方案,所以我实际上并没有找到所有答案。我只检查这样的解决方案 ((((10*7)-8)*3)+7)。所以即使我找到了组合,我也没有正确的顺序。
所以现在的问题是我如何测试所有可能的数学顺序,比如 (10*7)-(8*(3+7)), (10*7)-((8*3)+7 ) 或 10*(7-8)*(3+7)?我虽然可以使用带有操作的平衡树作为平衡节点。但我仍然不知道如何在不移动公式的情况下完成所有可能的组合。
(10*7)-(8*(3+7))
-
/ \
* *
/ \ / \
700 7 8 +
/ \
7 3
(10*7)-((8*3)+7)
-
/ \
* +
/ \ / \
700 7 * 7
/ \
8 3
10*(7-8)*(3+7)
*
/ \
*
/ \ 10
- +
/ \ / \
7 8 3 7
我如何在代码中执行此操作?不是在寻找已解决的代码更多的是我应该如何改变视角来修复它。我不知道为什么我被难住了。
关于我:第 4 年计算机科学,不是编程新手或菜鸟(我至少喜欢相信 ;))
使用表示表达式的专用 class 可以更容易地解决这个问题,而不是使用数组。然后你可以简单地枚举所有可能的树。 another answer that I wrote for a similar task, and an answer that shows how to generate all binary trees 的混合给出了这个:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class NumberPuzzleWithCats
{
public static void main(String[] args)
{
List<Integer> numbers = Arrays.asList(10,7,8,3,7);
solve(numbers);
}
private static void solve(List<Integer> numbers)
{
List<Node> nodes = new ArrayList<Node>();
for (int i=0; i<numbers.size(); i++)
{
Integer number = numbers.get(i);
nodes.add(new Node(number));
}
System.out.println(nodes);
List<Node> all = create(nodes);
System.out.println("Found "+all.size()+" combinations");
for (Node node : all)
{
String s = node.toString();
System.out.print(s);
if (s.equals("((10*7)-(8*(3+7)))"))
{
System.out.println(" <--- There is is :)");
}
else
{
System.out.println();
}
}
}
private static List<Node> create(Node n0, Node n1)
{
List<Node> nodes = new ArrayList<Node>();
nodes.add(new Node(n0, '+', n1));
nodes.add(new Node(n0, '*', n1));
nodes.add(new Node(n0, '-', n1));
nodes.add(new Node(n0, '/', n1));
nodes.add(new Node(n1, '+', n0));
nodes.add(new Node(n1, '*', n0));
nodes.add(new Node(n1, '-', n0));
nodes.add(new Node(n1, '/', n0));
return nodes;
}
private static List<Node> create(List<Node> nodes)
{
if (nodes.size() == 1)
{
return nodes;
}
if (nodes.size() == 2)
{
Node n0 = nodes.get(0);
Node n1 = nodes.get(1);
return create(n0, n1);
}
List<Node> nextNodes = new ArrayList<Node>();
for (int i=1; i<nodes.size()-1; i++)
{
List<Node> s0 = create(nodes.subList(0, i));
List<Node> s1 = create(nodes.subList(i, nodes.size()));
for (Node n0 : s0)
{
for (Node n1 : s1)
{
nextNodes.addAll(create(n0, n1));
}
}
}
return nextNodes;
}
static class Node
{
int value;
Node left;
Character op;
Node right;
Node(Node left, Character op, Node right)
{
this.left = left;
this.op = op;
this.right = right;
}
Node(Integer value)
{
this.value = value;
}
@Override
public String toString()
{
if (op == null)
{
return String.valueOf(value);
}
return "("+left.toString()+op+right.toString()+")";
}
}
}
它将打印所有创建的组合,包括您一直在寻找的组合:
[10, 7, 8, 3, 7]
Found 16384 combinations
(10+(7+(8+(3+7))))
(10*(7+(8+(3+7))))
...
((10*7)+(8*(3+7)))
((10*7)*(8*(3+7)))
((10*7)-(8*(3+7))) <--- There is is :)
((10*7)/(8*(3+7)))
((8*(3+7))+(10*7))
...
((7/3)-((8/7)/10))
((7/3)/((8/7)/10))
当然,通过比较String
表示来检查是否找到正确的解决方案是... "very pragmatic",这样说,但我认为生成的实际方法是这里重要的是什么。
(我希望这真的是您一直在寻找的 - 我无法查看您链接到的网站...)
为了好玩,我决定编写一个简单的程序来解决 10 只猫中有 8 只猫会倒计时 number puzzle,link 是倒计时形式,但规则相同。所以我的程序简单地遍历了 AxBxCxDxExF 的所有可能组合,其中字母是数字,"x" 是 +、-、/ 和 *。这是它的代码:
private void combineRecursive( int step, int[] numbers, int[] operations, int combination[]){
if( step%2==0){//even steps are numbers
for( int i=0; i<numbers.length; i++){
combination[ step] = numbers[ i];
if(step==10){//last step, all 6 numbers and 5 operations are placed
int index = Solution.isSolutionCorrect( combination, targetSolution);
if( index>=0){
solutionQueue.addLast( new Solution( combination, index));
}
return;
}
combineRecursive( step+1, removeIndex( i, numbers), operations, combination);
}
}else{//odd steps are operations
for( int i=0; i<operations.length; i++){
combination[ step] = operations[ i];
combineRecursive( step+1, numbers, operations, combination);
}
}
}
这是我用来测试组合是否符合我的要求的方法。
public static int isSolutionCorrect( int[] combination, int targetSolution){
double result = combination[0];
//just a test
if( Arrays.equals( combination, new int[]{100,'*',7,'-',8,'*',3,'+',7,'+',50})){
System.out.println( "found");
}
for( int i=1; i<combination.length; i++){
if(i%2!=0){
switch( (char)combination[i]){
case '+': result+= combination[++i];break;
case '-': result-= combination[++i];break;
case '*': result*= combination[++i];break;
case '/': result/= combination[++i];break;
}
}
if( targetSolution==result){
return i;
}
}
return targetSolution==result?0:-1;
}
所以在上一集中我发现我的代码有问题。这是其中一个难题的解决方案。
(10*7)-(8*(3+7))
我注意到我确实找到了这个组合“10*7-8*3+7”(两次),但是因为我通过从左到右的操作来检查解决方案,所以我实际上并没有找到所有答案。我只检查这样的解决方案 ((((10*7)-8)*3)+7)。所以即使我找到了组合,我也没有正确的顺序。
所以现在的问题是我如何测试所有可能的数学顺序,比如 (10*7)-(8*(3+7)), (10*7)-((8*3)+7 ) 或 10*(7-8)*(3+7)?我虽然可以使用带有操作的平衡树作为平衡节点。但我仍然不知道如何在不移动公式的情况下完成所有可能的组合。
(10*7)-(8*(3+7))
-
/ \
* *
/ \ / \
700 7 8 +
/ \
7 3
(10*7)-((8*3)+7)
-
/ \
* +
/ \ / \
700 7 * 7
/ \
8 3
10*(7-8)*(3+7)
*
/ \
*
/ \ 10
- +
/ \ / \
7 8 3 7
我如何在代码中执行此操作?不是在寻找已解决的代码更多的是我应该如何改变视角来修复它。我不知道为什么我被难住了。
关于我:第 4 年计算机科学,不是编程新手或菜鸟(我至少喜欢相信 ;))
使用表示表达式的专用 class 可以更容易地解决这个问题,而不是使用数组。然后你可以简单地枚举所有可能的树。 another answer that I wrote for a similar task, and an answer that shows how to generate all binary trees 的混合给出了这个:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class NumberPuzzleWithCats
{
public static void main(String[] args)
{
List<Integer> numbers = Arrays.asList(10,7,8,3,7);
solve(numbers);
}
private static void solve(List<Integer> numbers)
{
List<Node> nodes = new ArrayList<Node>();
for (int i=0; i<numbers.size(); i++)
{
Integer number = numbers.get(i);
nodes.add(new Node(number));
}
System.out.println(nodes);
List<Node> all = create(nodes);
System.out.println("Found "+all.size()+" combinations");
for (Node node : all)
{
String s = node.toString();
System.out.print(s);
if (s.equals("((10*7)-(8*(3+7)))"))
{
System.out.println(" <--- There is is :)");
}
else
{
System.out.println();
}
}
}
private static List<Node> create(Node n0, Node n1)
{
List<Node> nodes = new ArrayList<Node>();
nodes.add(new Node(n0, '+', n1));
nodes.add(new Node(n0, '*', n1));
nodes.add(new Node(n0, '-', n1));
nodes.add(new Node(n0, '/', n1));
nodes.add(new Node(n1, '+', n0));
nodes.add(new Node(n1, '*', n0));
nodes.add(new Node(n1, '-', n0));
nodes.add(new Node(n1, '/', n0));
return nodes;
}
private static List<Node> create(List<Node> nodes)
{
if (nodes.size() == 1)
{
return nodes;
}
if (nodes.size() == 2)
{
Node n0 = nodes.get(0);
Node n1 = nodes.get(1);
return create(n0, n1);
}
List<Node> nextNodes = new ArrayList<Node>();
for (int i=1; i<nodes.size()-1; i++)
{
List<Node> s0 = create(nodes.subList(0, i));
List<Node> s1 = create(nodes.subList(i, nodes.size()));
for (Node n0 : s0)
{
for (Node n1 : s1)
{
nextNodes.addAll(create(n0, n1));
}
}
}
return nextNodes;
}
static class Node
{
int value;
Node left;
Character op;
Node right;
Node(Node left, Character op, Node right)
{
this.left = left;
this.op = op;
this.right = right;
}
Node(Integer value)
{
this.value = value;
}
@Override
public String toString()
{
if (op == null)
{
return String.valueOf(value);
}
return "("+left.toString()+op+right.toString()+")";
}
}
}
它将打印所有创建的组合,包括您一直在寻找的组合:
[10, 7, 8, 3, 7]
Found 16384 combinations
(10+(7+(8+(3+7))))
(10*(7+(8+(3+7))))
...
((10*7)+(8*(3+7)))
((10*7)*(8*(3+7)))
((10*7)-(8*(3+7))) <--- There is is :)
((10*7)/(8*(3+7)))
((8*(3+7))+(10*7))
...
((7/3)-((8/7)/10))
((7/3)/((8/7)/10))
当然,通过比较String
表示来检查是否找到正确的解决方案是... "very pragmatic",这样说,但我认为生成的实际方法是这里重要的是什么。
(我希望这真的是您一直在寻找的 - 我无法查看您链接到的网站...)