题目描述
计算24点是一种扑克牌益智游戏,随机抽出4张扑克牌,通过加(+),减(-),乘(*), 除(/)四种运算法则计算得到整数24,本问题中,扑克牌通过如下字符或者字符串表示,其中,小写joker表示小王,大写JOKER表示大王: 3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER本程序要求实现:输入4张牌,输出一个算式,算式的结果为24点。详细说明:1.运算只考虑加减乘除运算,没有阶乘等特殊运算符号,友情提醒,整数除法要当心;2.牌面2~10对应的权值为2~10, J、Q、K、A权值分别为为11、12、13、1;3.输入4张牌为字符串形式,以一个空格隔开,首尾无空格;如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算;4.输出的算式格式为4张牌通过+-*/四个运算符相连,中间无空格,4张牌出现顺序任意,只要结果正确;5.输出算式的运算顺序从左至右,不包含括号,如1+2+3*4的结果为246.如果存在多种算式都能计算得出24,只需输出一种即可,如果无法得出24,则输出“NONE”表示无解。
输入描述
输入4张牌为字符串形式,以一个空格隔开,首尾无空格;
输出描述
如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算;
输入例子
A A A A
输出例子
NONE
算法实现
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("data2.txt")); while (scanner.hasNextLine()) { String input = scanner.nextLine(); System.out.println(solve(input)); } scanner.close(); } /** * 进行24点运算,假设输入的牌都是合法的 * * @param input 输入的牌 * @return 结果 */ private static String solve(String input) { // 有王 if (input.contains("joker") || input.contains("JOKER")) { return "ERROR"; } String[] parts = input.split("(\\s)+"); // 不是四个牌 if (parts.length != 4) { return "ERROR"; } // 将牌转换成数字 int[] ints = new int[parts.length]; for (int i = 0; i < ints.length; i++) { ints[i] = convert(parts[i]); } String[] r = {""}; boolean result = point24(ints, r); // 有结果 if (result) { return r[0]; } return "ERROR"; } /** * 4个[1, 13]的能否通过加减乘除,得到数字为24 * * @param opd 四个元素的数组 * @param r 用于保存结果 * @return true,可以组成24,false不可以组成24 */ private static boolean point24(int[] opd, String[] r) { char[] opt = new char[opd.length - 1]; char[] all = {'+', '-', '*', '/'}; return point24(opd, opt, all, 0, r); } /** * @param opd 操作数 * @param opt 用于计算的操作符 * @param all 可以使用的全部操作符 * @param n 当前处理的数 * @param r 用于保存表达式结果 * @return true,计算的值为24,false,计算的值不是24 */ private static boolean point24(int[] opd, char[] opt, char[] all, int n, String[] r) { // 处理最后一个数字 if (n == opd.length - 1) { if (calculate(opd, opt, r)) { return true; } } else { for (int i = n; i < opd.length; i++) { int temp = opd[n]; opd[n] = opd[i]; opd[i] = temp; for (char a : all) { opt[n] = a; boolean find = point24(opd, opt, all, n + 1, r); if (find) { return true; } } // 现场还原 temp = opd[n]; opd[n] = opd[i]; opd[i] = temp; } } return false; } /** * 计算值 * * @param opd 操作数 * @param opt 操作符 * @param r 保存结果表达式 * @return true,结果为24,false结果不是24 */ private static boolean calculate(int[] opd, char[] opt, String[] r) { double v = opd[0]; for (int i = 0; i < opt.length; i++) { v = calculate(v, opd[i + 1], opt[i]); } boolean eq = Math.abs(v - 24) < 0.0000001; if (eq) { r[0] = convert(opd[0]); for (int i = 0; i < opt.length; i++) { r[0] = r[0] + opt[i] + convert(opd[i + 1]); } } return eq; } /** * 将牌转换成对应的数值 * * @param s 牌 * @return 数值 */ private static int convert(String s) { if (s.length() == 1) { char c = s.charAt(0); if (c >= '2' && c <= '9') { return c - '0'; } switch (c) { case 'J': return 11; case 'Q': return 12; case 'K': return 13; case 'A': return 1; default: // do nothing } } else { switch (s) { case "10": return 10; default: // do nothing } } throw new RuntimeException("参数错误:" + s + ",只能输入[2, 10]、J、Q、K、A"); } /** * 将数值转换成牌 * * @param i 数值 * @return 牌 */ private static String convert(int i) { if (i >= 2 && i <= 10) { return "" + i; } switch (i) { case 1: return "A"; case 11: return "J"; case 12: return "Q"; case 13: return "K"; default: // do nothing } throw new RuntimeException("参数错误:" + i + ",牌值[1, 13]的整数"); } /** * 表达式求值 * * @param a 操作数一 * @param b 操作数二 * @param opt 操作符 * @return 运算结果 */ private static double calculate(double a, double b, int opt) { switch (opt) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: // do nothing } throw new RuntimeException("参数错误:" + ((char) opt) + "计算操作只支持加(+)、减(-)、*(乘)、除(、)"); }}