您的位置:首页 > 其它

24点游戏算法

2017-01-18 00:00 197 查看

题目描述

给出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;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: