題目描述
給出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;
}
}