`

二十四点算法

    博客分类:
  • Java
阅读更多
package com.onezero;
/**
 * <b>计算24游戏</b>
 * <br/>
 * 给出四张1到13之间的整数,通过+、-、*、/、()组合成合法表达式并使结果等于24;
 * 如给出1、3、4、6,可以组合乘6/(1-(3/4))
 * <br/>
 * 算法仍然是穷举法,不过删除了一些重复的式子。
 * 为了精确表示除法结果,这里实现<code>有理数</code>类。
 * 基本思想:先在四张牌中选出两张,有6种,再计算这两张牌的值,有5种;
 * 剩下两张牌及刚才计算的值可看作三张牌。在选择两张,有3种;
 * 再计算,又有5种,最后剩下两张,在计算,又是5种;最后比较这些值是否等于24即可。
 * 共有6*5*3*5*5=2250
 * <br/>
 * <b>没有除去连乘和连加的重复</b>
 * <br/>
 * <b>使用方法:</b><code>com.onezero.算24.计算二十四(new int[]{1,3,4,6})</code>
 * @see com.onezero.有理数
 * @version 	1.0, 2009年1月18日
 * @author Anguo Wen
 *
 */
public final class 算24 {
	private static int[] 四选二 = { 0, 1, 2, 3,  0, 2, 1, 3,  0, 3, 1, 2,  
		1, 2, 0, 3,  1, 3, 0, 2,  2, 3, 0, 1 };
	private static int[] 三选二 = { 0, 1, 2,  0, 2, 1,  1, 2, 0 };
	private static StringBuilder 表达式;
	
	/**
	 * 计算二十四,如果有解,打印出所有的解(删除部分重复解)
	 * 
	 * @param 四张牌 输入的四张1到13之间的牌
	 * @return 是否可以算的24
	 * @throws  ArithmeticException  如果参数 <code>四张牌</code> 少于四个数.
	 */
	public static boolean 计算二十四(final int[] 四张牌) {
		if(四张牌.length<4)throw new ArithmeticException("必须为四张牌");
		有理数[] 纸牌 = new 有理数[4];
		for(int h=0;h<4;h++)纸牌[h] = new 有理数(四张牌[h]);
		boolean 成功 = false;
		有理数[] 临时 = new 有理数[4];
		String[] 输出 = new String[4];
		有理数 结果;
		四张: for (int i = 0; i < 四选二.length; i += 4) {
			for (int t = 0; t < i; t += 4) {
				if (重复(纸牌[四选二[i]], 纸牌[四选二[i + 1]], 纸牌[四选二[t]], 纸牌[四选二[t + 1]]))
					continue 四张;
			}
			for (int j = 0; j < 5; j++) {
				if (继续(纸牌[四选二[i]], 纸牌[四选二[i + 1]], j))
					continue;
				临时[0] = 计算(纸牌[四选二[i]], 纸牌[四选二[i + 1]], j,
						纸牌[四选二[i]].toString(), 纸牌[四选二[i + 1]].toString());
				输出[0] = 表达式.toString();
				临时[1] = 纸牌[四选二[i + 2]];
				输出[1] = 临时[1].toString();
				临时[2] = 纸牌[四选二[i + 3]];
				输出[2] = 临时[2].toString();

				三张: for (int k = 0; k < 三选二.length; k += 3) {
					for (int s = 0; s < k; s += 3) {
						if (重复(临时[三选二[k]], 临时[三选二[k + 1]], 临时[三选二[s]],
								临时[三选二[s + 1]]))
							continue 三张;
					}

					if (k >= 6)
						for (int r = 0; r < i; r += 4) {
							if (重复(临时[三选二[k]], 临时[三选二[k + 1]], 纸牌[四选二[r]],
									纸牌[四选二[r + 1]]))
								continue 三张;
						}
					for (int l = 0; l < 5; l++) {
						if (继续(临时[三选二[k]], 临时[三选二[k + 1]], l))
							continue;
						临时[3] = 计算(临时[三选二[k]], 临时[三选二[k + 1]], l, 输出[三选二[k]],
								输出[三选二[k + 1]]);
						输出[3] = 表达式.toString();
						for (int m = 0; m < 5; m++) {
							if (继续(临时[三选二[k + 2]], 临时[3], m))
								continue;
							结果 = 计算(临时[三选二[k + 2]], 临时[3], m, 输出[三选二[k + 2]],
									输出[3]);

							if (结果.等于(24)) {
								System.out.print(表达式.substring(1,
										表达式.length() - 1) + "\t");
								成功 = true;
							}
						}

					}
				}
			}
		}
		return 成功;
	}

	private static boolean 重复(有理数 数一, 有理数 数二, 有理数 数三, 有理数 数四) {
		return (数一.equals(数三) && 数二.equals(数四))
				|| (数一.equals(数四) && 数二.equals(数三));
	}

	private static boolean 继续(有理数 数一, 有理数 数二, int 运算符) {
		switch (运算符) {
		case 1:
			return 数一.equals(数二);
		case 2:
			return 数一.等于(2) && 数二.等于(2);
		case 3:
			return 数二.等于(1);
		case 4:
			return 数一.等于(1) || 数一.equals(数二);
		default:
			return false;
		}
	}

	private static 有理数 计算(有理数 分数一, 有理数 分数二, int 运算符, String 式一, String 式二) {
		表达式 = new StringBuilder("(");
		switch (运算符) {
		case 0:// 分数一+分数二
			表达式.append(式一).append("+").append(式二).append(")");
			return 分数一.加(分数二);
		case 1:// |分数一-分数二|
			有理数 结果 = 分数一.减(分数二);
			if (结果.小于零()) {
				结果.负();
				表达式.append(式二).append("-").append(式一).append(")");
			} else 
				表达式.append(式一).append("-").append(式二).append(")");
			return 结果;
		case 2:// 分数一*分数二
			表达式.append(式一).append("*").append(式二).append(")");
			return 分数一.乘(分数二);
		case 3:// 分数一/分数二
			表达式.append(式一).append("/").append(式二).append(")");
			return 分数一.除(分数二);
		default:// 分数二/分数一
			表达式.append(式二).append("/").append(式一).append(")");
			return 分数二.除(分数一);
		}
	}
	
	/**
	 * 主函数 测试用
	 * 打印出所有的可能组合的解及有解组合的总数
	 * 输入命令java -cp 24点游戏.jar com.onezero.算24
	 * @param args
	 */
	public static void main(String[] args) {
		int 有解 = 0;
		for (int i = 1; i < 14; i++)
			for (int j = i; j < 14; j++)
				for (int k = j; k < 14; k++)
					for (int l = k; l < 14; l++)
						if (计算二十四(new int[] { i, j, k, l })) {
							System.out.println();
							有解++;
						}
		System.out.println(有解);
	}
}

class 有理数 {
	private int 分子;
	private int 分母 = 1;

	有理数(int 分子) {
		this.分子 = 分子;
	}

	有理数(int 分子, int 分母) {
		if (分母 <= 0)
			throw new ArithmeticException("分母不可小于等于零!");
		int 公约数 = 最大公约数(分子 < 0 ? -分子 : 分子, 分母);
		this.分子 = 分子 / 公约数;
		this.分母 = 分母 / 公约数;
	}

	public boolean 等于(int 整数) {
		return 整数 == this.分子 && 1 == this.分母;
	}

	private int 最大公约数(int 数一, int 数二) {
		if (数一 == 数二) {
			if (数一 == 0)
				throw new ArithmeticException("求最大公约数不可同时为零!");
			return 数一;
		}
		if (数一 == 0)
			return 数二;
		if (数二 == 0)
			return 数一;
		else if (数一 > 数二)
			return 最大公约数(数二, 数一 % 数二);
		else
			return 最大公约数(数一, 数二 % 数一);
	}

	public 有理数 加(有理数 分数二) {
		return new 有理数(this.分子 * 分数二.分母 + this.分母 * 分数二.分子, this.分母 * 分数二.分母);
	}

	public 有理数 减(有理数 分数二) {
		return new 有理数(this.分子 * 分数二.分母 - this.分母 * 分数二.分子, this.分母 * 分数二.分母);
	}

	public 有理数 乘(有理数 分数二) {
		return new 有理数(this.分子 * 分数二.分子, this.分母 * 分数二.分母);
	}

	public 有理数 除(有理数 分数二) {
		if (分数二.分子 == 0)
			throw new ArithmeticException("不可除零!");
		return new 有理数(this.分子 * 分数二.分母, this.分母 * 分数二.分子);
	}

	public boolean 小于零() {
		return this.分子 < 0;
	}

	public void 负() {
		this.分子 = -this.分子;
	}

	public String toString() {
		if (this.分母 == 1)
			return Integer.toString(this.分子);
		return this.分子 + "/" + this.分母;
	}

	public boolean equals(Object 数) {
		if (!(数 instanceof 有理数))
			return false;
		有理数 数二 = (有理数) 数;
		return this.分子 == 数二.分子 && this.分母 == 数二.分母;
	}
}
5
0
分享到:
评论

相关推荐

    c#关于24点算法

    24点算法是一种经典的数学游戏,源自中国的扑克牌游戏,目标是通过加减乘除运算,使四张1到13之间的数字牌得出24。在编程领域,我们可以用C#来实现这个算法,将其转化为计算机可以处理的问题。下面将详细探讨如何用...

    24点算法 (C++实现)

    C++ 递归实现24点算法, 输入数组,返回所有可以组成24点的结果,并且自动去重 结果为算式 如: (2+10)*2*1=24

    算24点 24点算法 源代码和程序

    《探究24点算法:源代码与程序解析》 24点游戏,作为一个经典而富有挑战性的数学游戏,深受广大玩家喜爱。它基于四则运算,通过加、减、乘、除运算,使得四个给定的自然数(通常是1到13之间)组合运算后得到结果为...

    24点算法的实现(24点游戏源码).

    24点游戏是一种广受欢迎的智力游戏,玩家需要在四张扑克牌中通过加减乘除运算找出一种或多种方式使结果等于24。在这个场景中,我们关注的是"24点算法的实现",这涉及到编程技术,尤其是C++语言,以及可能用到的图形...

    24点算法及程序

    标题中的“24点算法及程序”指的是一个数学游戏,玩家需要从四张包含1到13的扑克牌中,通过加、减、乘、除和括号的操作,使得计算结果等于24。这个概念在计算机编程中可以转化为一个算法问题,即编写一个程序来自动...

    24点算法 课程设计

    从给定的文件信息来看,这是一段关于24点算法的C++源代码,用于课程设计项目。24点游戏是一种数学游戏,通常由四张扑克牌组成,玩家需要利用加、减、乘、除(每张牌只能用一次)来使结果等于24。以下是对这段代码的...

    java 扑克牌24点算法

    本算法实现了24点游戏的基本功能,即给定四个数字(1-10),输出所有可能的运算方式使其结果等于24。该算法利用了多重循环来进行数据组合,并通过递归思想进行四则运算。需要注意的是,在实际开发过程中,为了提高...

    计算24点算法

    "计算24点"是一个经典的数学游戏,挑战玩家利用加减乘除运算符以及括号,将四张扑克牌上的数字组合成24。在这个问题中,我们要讨论的是实现这个功能的算法,即如何设计一个程序自动找到这些计算公式。 首先,我们...

    C#24点算法

    这是C#的控制台程序,用不到70行代码解决了24点游戏的算法问题。给出4个数字,能够计算4个数字加减乘除后得到24的所有式子。代码里对括号进行了处理。

    24点算法及算术运算算法

    首先,24点算法的核心在于如何有效地组合与排列这四张牌。这需要对数字的性质有深刻的理解,例如整除、余数、乘方等。在这个过程中,堆栈(Stack)数据结构扮演了重要的角色。堆栈是一种后进先出(LIFO)的数据结构...

    java 24 点算法

    一个java24点算法

    24点算法

    《24点算法详解——构建计算树探索游戏策略》 24点游戏,一个深受人们喜爱的智力挑战,它的目标是通过加、减、乘、除四种运算将四张牌的数值组合成24。自动求解24点的问题,实际上就是设计一个算法,能够系统地遍历...

    24点 自动求解程序_24点算法小程序_

    24点游戏是一种广受欢迎的智力游戏,玩家需要利用四张1到13的扑克牌,通过加减乘除运算,使得结果等于24。在这个背景下,"24点自动求解程序"是一个利用计算机算法解决24点问题的软件。这个程序可以帮玩家找出所有...

    基于24点算法的报告和总结

    24点算法是一种经典的数学游戏,目标是通过加、减、乘、除四种基本运算,使得四张1到10的扑克牌组合得出24点。在这个问题中,我们有40张扑克牌(每种1到10的数字各两张,不区分花色),每次从中随机抽取4张,尝试...

    24点算法,不正确你抽我

    24点算法,穷举12288种可能,不正确你抽我。

    算24点 算法经典 回溯法

    《算24点算法经典——回溯法解析》 在计算机科学中,算24点是一种基于数学和逻辑思维的游戏,玩家需要通过加、减、乘、除运算,以及括号的使用,使得四张扑克牌上的数字组合运算后得到24。这种问题的解决方法之一...

    24点算法,基于VC++

    24点算法是一种基于数学和逻辑的娱乐游戏,玩家需要从四张1-13的扑克牌中,通过加、减、乘、除运算,使得结果等于24。这个过程涉及到数学策略、逻辑推理以及计算机编程的实现。在本文中,我们将深入探讨如何使用C++...

    商业编程-源码-24点算法的实现.zip

    24点算法的基本规则是:从一副扑克牌(去掉大小王)中任意抽取四张,不论顺序,利用加、减、乘、除、括号这五种运算,每张牌只能用一次,使得结果等于24。这个问题可以转化为一个深度优先搜索(DFS)或回溯算法问题...

Global site tag (gtag.js) - Google Analytics