`
RednaxelaFX
  • 浏览: 3047737 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

那啥……穷举实现的24点

    博客分类:
  • Java
阅读更多
呵呵,最近面试某公司的同学真多。早就听说他们上机考试要考24点的实现了,不过没想到那么多个同学都遇到了这一题。这不,对面宿舍有同学又要去面那公司了,找我问这24点怎么写。考虑到也不能写太难得方法不然同学记起来麻烦,干脆就写了个超直观超naive的穷举实现。哈哈。

首先是24点问题的定义。我采纳的定义是用户可以输入4个数字,每个数字可接受的范围是1-13的整数;对这4个数字做4则混合运算得到的结果是24时,则这个表达式被认为符合题目条件。

然后考虑一下如何穷举。如果把四个数字固定顺序,则有时候需要插入括号来改变运算优先级来得到符合条件的表达式,但这样挺麻烦的。这里取个巧,不是插入括号,而是改变4个输入参数的前后顺序来改变运算的先后顺序。
可是加减与乘除的优先级不同,怎么办呢?再取个巧,使用后缀表达式来处理一切与运算优先级相关的问题。用了后缀表达式就不必为括号而头疼了。

所以我们得到的表达式的形式会是类似:
num1 num2 op1 num3 op2 num4 op3

或者:
num1 num2 op1 num3 num4 op2 op3

或者:
num1 num2 num3 op1 num4 op2 op3


例如说,1 2 + 3 + 4 ×就是(1 + 2 + 3) * 4。
于是我们对4个输入的数字的顺序做一个全排列,为每种排列情况再对其中3个间隔上的运算符做穷举。

然后来看看代码。为了让同学有足够东西可以说,我用了Java 5里的3种新特性:泛型、enum和for-each。

不过当前的实现下,会漏掉一些情况。下面的代码只实现了上面列举的3种可能的第一种。
hmm,那倒也不太算个问题,因为反正是他们面试嘛诶……呵呵,明天再把不会漏掉运算情况的穷举的代码发出来。

Calc24.java:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Calc24 {
    public static void main(String[] args) throws Exception {
        int[] input = promptInput();
        int length = input.length;
        ArrayList<TupleOfFour> permutation = new ArrayList<TupleOfFour>();

        // get permutation of the four operands
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                if (i == j) continue;
                for (int k = 0; k < length; ++k) {
                    if (i == k || j == k) continue;
                    int l = 6 - i - j - k;
                    permutation.add(new TupleOfFour(
                        input[i], input[j], input[k], input[l]));
                }
            }
        }

        // enumerate the operators, and evaluate the postfix expression
        for (TupleOfFour tuple : permutation) {
            int first = tuple.getFirst();
            int second = tuple.getSecond();
            int third = tuple.getThird();
            int fourth = tuple.getFourth();

            for (Operator op1 : Operator.values()) {
                if ((op1 == Operator.Divide) &&
                    !(Operator.canDivide(first, second))) continue;
                int result1 = op1.calculate(first, second);
                for (Operator op2 : Operator.values()) {
                    if ((op2 == Operator.Divide) &&
                        !(Operator.canDivide(result1, third))) continue;
                    int result2 = op2.calculate(result1, third);
                    for (Operator op3 : Operator.values()) {
                        if ((op3 == Operator.Divide) &&
                            !(Operator.canDivide(result2, fourth))) continue;
                        int result3 = op3.calculate(result2, fourth);
                        if (result3 == 24) {
                            // build a string representation
                            // of the postfix expression
                            StringBuilder builder = new StringBuilder();
                            builder.append(first);
                            builder.append(" ");
                            builder.append(second);
                            builder.append(" ");
                            builder.append(op1.getOpChar());
                            builder.append(" ");
                            builder.append(third);
                            builder.append(" ");
                            builder.append(op2.getOpChar());
                            builder.append(" ");
                            builder.append(fourth);
                            builder.append(" ");
                            builder.append(op3.getOpChar());

                            System.out.println(builder.toString());
                        } // end if
                    } // end of for-each op3
                } // end of for-each op2
            } // end of for-each op1
        } // end of for-each permutation
    } // end of main()

    private static int[] promptInput() throws Exception {
        int[] input = new int[4];
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(System.in));
        String line = null;

        for (int i = 0; i < 4; ++i) {
            System.out.print("Enter a number (1 to 13): ");
            line = reader.readLine();
            try {
                input[i] = Integer.parseInt(line);
                if (input[i] < 1 || input[i] > 13)
                    throw new IllegalArgumentException();
            } catch (IllegalArgumentException e) {
                System.out.println("The input is invalid. Please re-enter.");
                --i;
            }
        }

        return input;
    }
}


TupleOfFour.java:
public class TupleOfFour {
    private int first;
    private int second;
    private int third;
    private int fourth;
    
    public TupleOfFour(int first, int second, int third, int fourth) {
        this.first = first;
        this.second = second;
        this.third = third;
        this.fourth = fourth;
    }

    public int getFirst() {
        return first;
    }

    public int getSecond() {
        return second;
    }

    public int getThird() {
        return third;
    }

    public int getFourth() {
        return fourth;
    }
}


Operator.java:
public enum Operator {
    Add('+') {
        int calculate(int first, int second) {
            return first + second;
        }
    },
    Minus('-') {
        int calculate(int first, int second) {
            return first - second;
        }
    },
    Multiply('*') {
        int calculate(int first, int second) {
            return first * second;
        }
    },
    Divide('/') {
        int calculate(int first, int second) {
            return first / second;
        }
    };
    
    private char opChar;
    
    Operator(char c) {
        this.opChar = c;
    }
    
    abstract int calculate(int first, int second);
    
    public char getOpChar() {
        return this.opChar;
    }
    
    public static boolean canDivide(int first, int second) {
        return (first % second) == 0;
    }
}
分享到:
评论

相关推荐

    ACM程序设计培训教程

     15.6 应用…………………………………………………………………………………………………………227  〖案例l〗果园篱笆………………………………………………………………227  〖案例2〗巨人和鬼………………...

    还是24点……前两个都有问题……

    标题中的“还是24点……前两个都有问题……”暗示了这是一个关于解决24点游戏的问题,其中前两种尝试可能存在不足或错误。24点游戏是一个流行的心算游戏,玩家需要使用加减乘除四种基本运算,以及括号来重新组合给定...

    C++多重循环.ppt

    C++ 多重循环知识点总结 多重循环是 C++ 编程语言中一种常用的循环结构,指的是在一个循环体内嵌套另一个循环体。多重循环可以使用 for、while 和 do-while 语句来实现。 多重循环的基本格式: ```c for (……) { ...

    [文本穷举器]从表达式穷举文本-易语言

    //如果设计一个互斥组,可以实现m选n,目前不支持,不偏向这个,也没有更多括号了…… //*3~3 示例: qq 结果:qq00000,qq00001,qq00002,...qq99999的10w个字符串 id`8-80` 结果:id8,id9,id10,...id80 \time\ ...

    运动场选址数学建模.docx

    该问题基于18个居民点,部分点间存在道路连接,原有的四个运动场分别位于2、6、12、15号居民点。建模过程分为三个主要问题: 1. **问题一**:构建单目标优化模型。考虑到每个居民点的人口数量和到运动场的距离,...

    C语言程序设计课程设计题目.pdf

    C语言程序设计课程设计题目.pdf ...本文档提供了数据结构和算法、成绩排序、迷宫问题和栈及其操作等多个领域的知识点和实现要求,旨在帮助读者更好地理解和掌握C语言程序设计的知识点和应用领域。

    C语言经典例题100例

    ### 四、分数序列求和(程序24) **题目描述**:有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13……求出这个数列的前20项之和。 **解题思路**: 1. **规律**:观察数列可以发现,分子和分母之间存在一定的规律性...

    Java常用算法手册源代码

    **章 算法和实现算法的Java语法 1.1 建立算法初步概念 1.1.1 什么是算法 1.1.2 算法的发展历史 1.1.3 算法的分类 1.2 算法相关概念的区别 1.2.1 算法与公式的关系 1.2.2 算法与程序的关系 1.2.3 算法与数据结构的...

    解01背包问题的动态规划算法.doc

    通过研究动态规划原理,提出了根据该原理解决0/1背包问题的方法与算法实现,并对算法的正确性作了验证。 动态规划原理是通过将问题分解成多个阶段,每个阶段的决策都是基于前一个阶段的决策,以此来达到最优解。...

    经典问题的回溯算法

    2. **控制策略**:为了提高效率,避免不必要的穷举搜索,回溯算法会在搜索过程中遇到失败时,回溯到上一个决策点,尝试不同的路径。 3. **数据结构**:使用数组来存储搜索过程中各种状态和路径信息。 #### 四、回溯...

    初级C++练习题

    ### 知识点总结 #### 1. 直角三角形面积最大问题 **知识点概述:** 本题涉及数组处理、排序以及勾股定理的应用。对于初学者来说,这是一道很好的练习题,旨在帮助他们熟悉C++中的基本数据结构和算法。 **详细解析...

    C 程序开发经典实例之三

    第二天早上又将剩下的桃子吃掉一半,又多吃了一个……以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少个桃子。 #### 解决思路 - **逆向思维**:从最后一...

    【09-异常处理】

     –无法穷举所有异常情况:因为人类知识的限制,异常情况总比可以考虑到的情况多,总有“漏网之鱼”的异常情况,所以程序总是不够健壮。  –错误处理代码和业务实现代码混杂:这种错误处理和业务实现混杂的代码...

    软件测试 面试题大全

    #### 24. 你认为做好测试计划工作的关键是什么? 做好测试计划的关键在于: - **明确目标**:明确测试的目的和范围。 - **充分准备**:准备必要的资源,包括人员、工具和环境。 - **合理安排**:制定合理的测试计划...

Global site tag (gtag.js) - Google Analytics