24點遊戲算法

題目描述

給出4個1-10的數字,經過加減乘除,獲得數字爲24就算勝利
輸入:
4個1-10的數字。[數字容許重複,測試用例保證無異常數字]
輸出:
true or false

輸入描述

輸入4個int整數

輸出描述

返回可否獲得24點,能輸出true,不能輸出false

輸入例子

7 2 1 10

輸出例子

true

算法實現

import java.util.LinkedList;
import java.util.Scanner;

/**
 * Declaration: All Rights Reserved !!!
 */
public class Main {


    public static void main(String[] args) {
//        Scanner scanner = new Scanner(System.in);
        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt"));
        while (scanner.hasNext()) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            int c = scanner.nextInt();
            int d = scanner.nextInt();

            System.out.println(game24Points(a, b, c, d));

        }
        scanner.close();
    }

    // a, b, c, d都在[1, 10]內

    /**
     * 4個[1, 10]的可否經過加減乘除,獲得數字爲24
     *
     * @param a 第一個數字
     * @param b 第二個數字
     * @param c 第三個數字
     * @param d 第四個數字
     * @return true,能夠組成24,false不能夠組成24
     */
    private static boolean game24Points(int a, int b, int c, int d) {
        int[] arr = {a, b, c, d, '+', '-', '*', '/'};
        boolean[] used = new boolean[arr.length];
        LinkedList<Integer> list = new LinkedList<Integer>();

        boolean[] rst = {false};

        // 構造組合的逆波蘭表達式
        for (int i = 0; i < 4; i++) {
            used[i] = true;
            list.add(arr[i]);
            to24(arr, used, 1, 0, list, rst);

            if (rst[0]) {
                return true;
            }

            // 現場還原
            list.removeLast();
            used[i] = false;
        }


        return false;
    }

    /**
     * 4個[1, 10]的可否經過加減乘除,獲得數字爲24
     *
     * @param arr    可以使用的操做數、操做符的數組
     * @param used   已經使用的操做數、操做符標記數組
     * @param numCnt 操做數的個數
     * @param optCnt 操做符的個數
     * @param list   求得的逆波蘭式
     * @param rst    保存中間結果,有知足24的就中止計算
     */
    private static void to24(int[] arr, boolean[] used, int numCnt, int optCnt,
                             LinkedList<Integer> list, boolean[] rst) {


        // 若是已經找到答案就不進行操做了
        if (rst[0]) {
            return;
        }
        // 已經完成了逆波蘭式的構造
        if (numCnt > optCnt && numCnt + optCnt == 7) {
            calInversePoland(list, rst);
        }
        // 還要構造逆波蘭式
        else if (numCnt > optCnt) {

            for (int i = 0; i < arr.length; i++) {
                // 若是arr[i]尚未被使用過,或者arr[i]是運算符
                if (!used[i] || arr[i] < 0 || arr[i] > 10) {
                    // 若是是數字
                    if (arr[i] >= 0 && arr[i] <= 10) {
                        list.add(arr[i]);
                        numCnt++;
                        used[i] = true;

                        to24(arr, used, numCnt, optCnt, list, rst);

                        // 找到了一個答案就返回
                        if (rst[0]) {
                            return;
                        }

                        list.removeLast();
                        numCnt--;
                        used[i] = false;

                    }
                    // 若是是操做符,則放入arr[i]以前,操做數必須比操做符多兩個
                    else if (numCnt + 1 > optCnt) {
                        list.add(arr[i]);
                        optCnt++;
                        used[i] = true;

                        to24(arr, used, numCnt, optCnt, list, rst);

                        // 找到了一個答案就返回
                        if (rst[0]) {
                            return;
                        }
                        list.removeLast();
                        optCnt--;
                        used[i] = false;
                    }
                }
            }

        }


    }

    /**
     * 計算逆波蘭式的值
     *
     * @param list 逆波蘭式
     * @param rst  用於保存計算結果
     */
    private static void calInversePoland(LinkedList<Integer> list, boolean[] rst) {
        LinkedList<Double> stack = new LinkedList<>();

        for (int v : list) {

            // 若是是數字
            if (v >= 0 && v <= 10) {
                stack.add((double)v);
            } else {
                double a = stack.removeLast();
                double b = stack.removeLast();
                double c = 0;
                switch ((char) v) {
                    case '+':
                        c = a + b;
                        break;
                    case '-':
                        c = a - b;
                        break;
                    case '*':
                        c = a * b;
                        break;
                    case '/':
                        // 除數不能爲0
                        if (a == 0) {
                            return;
                        }
                        c = b / a;
                        break;
                }

                stack.add(c);
            }
        }



        rst[0] = stack.getFirst() == 24.0;
    }

}
相關文章
相關標籤/搜索