24点游戏:java的一种穷举实现

来源:互联网 发布:.net软件开发 编辑:程序博客网 时间:2024/05/20 20:21

24点游戏:java的一种穷举实现

创号以来的第一篇博客,希望看到的各位都支持下哈。


24点纸牌游戏是我很喜欢的一个游戏,一直没有编程去实现过,百度百科就有提供的方法去实现这一算法,用到了中缀及后缀表达式。而我也在周一的时候自己尝试实现了这个程序:这里提供的是一种穷举法的思路。


实现是用的java,首先还是先说一下规则吧:
  有四种花色的扑克牌,大小都是从1到10,现在从中选取4张牌,计算这四张牌的算术组合结果能否等于24.
  例如这么一组数:
5 5 5 1
对于这一组数,如何让它构成24点呢?答案是:5 × (5 - (1 ÷ 5)) = 24 。 
  
  
题目思路:
一、一般思路:
这道题的思路首先想到的肯定是穷举,那么究竟会有哪些情况呢?

没有括号的情况:
一共4个数,4的情况下一共4个数,4! = 24 种情况;三个运算符,每个运算符只可能是(+ - x ÷)中的一种,4^3 = 64 种情况。


有括号的情况:
1、形如 (a * b) * c * d);
2、形如 (a * b * c) * d);
3、形如 a * (b * c) * d);
4、形如 (a * b) * (c * d));
5、形如 ((a * b) * c) * d);
6、形如 (a * (b * c)) * d);

对于上述思路来说,实现的话就是穷举出来所有数,所有运算符以及所有括号可能的情况,然后一一计算判断。这样的话情况应该也不会特别多,至少是计算机可以接受的范围。但是括号的形式太多了,穷举之后一定要通过 递归+回溯 来实现所有可能情况的判断,对于上述情况来说,可能的情况太多,也许在编码的时候自己就会凌乱了,所以虽说要穷举,但是也要对于穷举的方式给予一定的修改。


二、穷举整改后的思路:

假设我们用⊙表示运算,⊙除了可以表示基本的 "+", "-", "x", "÷"外。我们还引入两个新的运算,"反-",和"反÷"。


比如(a 反÷ b)的意思是(b ÷ a)。则对形如(c ÷ (a + b))的形式,就可以等价的描述为((a + b) 反/ c)。
这样描述可以减少算式中括号的情况。
利用这6种运算,可以将所有可能的计算过程归结为2类:
(((a ⊙ b) ⊙ c ) ⊙ d)
((a ⊙ b) ⊙ (c ⊙ d))

将4张牌的值,分别代入a,b,c,d,再把可能的运算符也代入。就可以得到相应的计算式子,将其计算出来,再检查结果是否等于24。

由于有4个数,所以对于a,b,c,d的对应关系有 4!=24 种情况。3个运算符,每个运算符可能有6种情况,那就是 6^3 = 216。再考虑到2种不同的模式,所以一共有2 * 24 * 216 = 10368种情况。


在这么多中情况中肯定会有重复的情况,所以在此基础上可以对其进行剪枝,但是剪起来会相当麻烦,所以这里就不再剪了,一万种情况对于计算机来说还是可以满足的。私下里可以再尝试对这种算法的剪枝。所以到这一步,就可以代码实现了:


下面附上我的代码:
import java.util.Scanner;public class Point24 {boolean used[] = { false, false, false, false };float nowNumber[] = { 0, 0, 0, 0 };float number[] = { 0, 0, 0, 0 };int[] ops = { 0, 0, 0 };int opType[] = { 1, 2, 3, 4, 5, 6 };public void getInput(Scanner scan) {for (int i = 0; i < 4; i++) {number[i] = scan.nextFloat();}}public boolean makeNumber(int depth) {if (depth >= 4) {// 此时已经枚举完四个数了,// 开始枚举运算符return makeOperation(0);}for (int i = 0; i < 4; i++) {if (!used[i]) {nowNumber[depth] = number[i];used[i] = true;if (makeNumber(depth + 1)) {return true;}used[i] = false;}}return false;}public boolean makeOperation(int depth) {if (depth >= 3) {// 此时已经枚举了四个数和三个运算符// 计算第一种模式下的值if (calcType1() == 24.0) {return true;}if (calcType2() == 24.0) {return true;}return false;}for (int i = 0; i < 6; i++) {ops[depth] = opType[i];if (makeOperation(depth + 1))return true;}return false;}public float calculate(float a, float b, int type) {switch (type) {case 1:return (a + b);case 2:return (a - b);case 3:return (a * b);case 4:if (b == 0)return 0;return (a / b);case 5:return (b - a);case 6:if (a == 0)return 0;return (b / a);}return 0;}public float calcType1() {float result = nowNumber[0];result = calculate(result, nowNumber[1], ops[0]);result = calculate(result, nowNumber[2], ops[1]);result = calculate(result, nowNumber[3], ops[2]);return result;}public float calcType2() {float result1 = nowNumber[0];float result2 = nowNumber[2];result1 = calculate(result1, nowNumber[1], ops[0]);result2 = calculate(result2, nowNumber[3], ops[2]);result1 = calculate(result1, result2, ops[1]);return result1;}public static void main(String[] args) {Scanner scan = new Scanner(System.in);int n = scan.nextInt();String result[] = new String[n];Point24 point;for (int i = 0; i < n; i++) {point = new Point24();point.getInput(scan);result[i] = point.makeNumber(0) ? "Yes" : "No";}for (int i = 0; i < n; i++) {System.out.println(result[i]);}}}





0 0