24点算法详解--Java代码实现
来源:互联网 发布:淘宝全球购申请入口 编辑:程序博客网 时间:2024/05/18 01:02
在网上看了很多的24点,结果都不尽人意,然后从学长那弄来了代码仔细研究了一番,以下是我对该算法原理及实现的理解
注:对于52张 扑克牌构成的27万多种可能的组合,代码经测试最快能达到0.35秒,即可计算出所有解得情况,本文就输入四个数,得到其所有24点的解的高效的算法进行详解
理解原理(前提):
1.采用四元转三元, 三元转二元,二元转一元的方法,在有四个数时,我们取出其中两个数,进行加减乘除运算,返回一个数,这样就实现了四元到三元的简化。
PS:到这里你可能会问了,我怎么知道该取那两个数。回答:这里我们取数是根据优先级来的(这里能理解吧,优先级高的肯定是要先计算的呀)。
例如:a,b,c,d四个数,在计算时,要么我们先计算a,b,要么我们先计算b,c要么我们先计算c,d,所以,到底该取两个数,其实已经很明了了,如果还有什么问题,等会可以看看下面的代码。
三元到二元也是同样的道理,最后二元到一元,就可以得到结果了。
2.对于四个数,根据算术优先级,从高到低,一定会有三个运算符。
3.由1,2我们就可以大概了解了,我们可以通过组合不同的优先级顺序,然后尝试在各个优先级计算中添加不同的运算符,就可以得到各种结果
步骤:
1.输入四个数,对这四个数进行排列组合,比如(10,2,3,6)有(2,3,10,6),(2,6,10,3)等这些组合呀,以便构成不同的算式。
2.采用三重循环的方式,每一次循环都会是不同的运算符,这一步是为了得到各种运算符的组合。
3,然后在三重循环里面,分别进行优先级组合,同时进行计算,将四元转化为三元,如下,这里只展示了四元转三元,三元转二元,同理,这一步是为了得到各个优先级层次上的各种组合。与步骤2一起构成了所有的组合。
PS:这里看不懂也没关系,等会将代码全部连通了看,就会明了些了
贴代码:
PS:
allResult()方法是对52张扑克牌进行的组合,如果你需要的不是扑克牌的话,请自行更改,然后这里的所有方法为静态方法,便于调用。
PS:
对扑克牌游戏算法的优化方法,来源于我的另一位同学,真的厉害,我只是代码的搬运工/笑哭
times(int i,int j,int k,int l)方法是为了避免扑克牌花色的重复,如果你不需要,可以直接忽略
import java.util.ArrayList;import java.util.HashSet;import java.util.Set;public class CalculateRatio { // 将4个操作数简化为3个操作数时,将这三个操作数存放在temp1中 private static double[] temp1 = new double[3]; // 将3个操作数简化为2个操作数时,将这两个操作数存放在temp2中 private static double[] temp2 = new double[2]; private static double sum; private static int[] cardArray = new int[4]; private static char[] operator = { '+', '-', '*', '/' }; private static double[] scard = new double[4]; private static boolean isCorrect = false; /** * 列出所有不重复的组合 */ public static void allResult() { int allcount = 0; int count = 0; int times = 0; // 这里只考虑对数据 // 为了减少运算量,避免重复的排列组合,比如1,2,3,4与1,2,4,3,这样就是重复的,采用了j = i, k = j这种来控制循环 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++) { //判断花色重复的数量 times = times(i, j, k, l); allcount += times; // 判断该表达式是否正确 if (getExpression(i, j, k, l) != null) { count += times; } } } } double rate = (double) count / allcount; System.out.println("所有可能的组合共有:" + allcount); System.out.println("结果为24的组合共有: " + count); System.out.println("成功的几率是:" + rate); } /** * 方法简述:输入4个数判断其能产生多少个结果等于24的算式,就是选出来的四个数一个会有多少种排列组合,这样是为了得到更多 * * @param i * @param j * @param k * @param l * @return */ public static ArrayList<String> getExpression(int num1, int num2, int num3, int num4) { //声明一个ArrayList,用于存放所有可能的表达式 ArrayList<String> expressionList = new ArrayList<String>(); for (int a = 0; a < 4; a++) for (int b = 0; b < 4; b++) { // 这些判断是为了防止产生错误的组合,比如传进来的数是1,4,6,8,如果没有判断,就可能导致产生1,1,6,8这种组合 if (b == a) { continue; } for (int c = 0; c < 4; c++) { if (c == a || c == b) { continue; } for (int d = 0; d < 4; d++) { if (d == a || d == b || d == c) { continue; } // 让四个数产生了不同的组合,比如1,4,6,8--8,1,6,4等 cardArray[a] = num1; cardArray[b] = num2; cardArray[c] = num3; cardArray[d] = num4; for (int m = 0; m < 4; m++) { // 这里转换为double类型是为了方便后面的除法运算 scard[m] = (double) cardArray[m] % 13; if (cardArray[m] % 13 == 0) { scard[m] = 13; } } // 进行一次搜索 expressionList = search(); // 如果搜索出来的是正确的,那么将isCorrect置为false,便于下次使用 if (isCorrect) { isCorrect = false; return expressionList; } } } } return null; } /** * 方法简述:基本计算 * * @param number1 * 数字1 * @param number2 * 数字2 * @param operator * 数字3 * @return */ private static double calcute(double number1, double number2, char operator) { if (operator == '+') { return number1 + number2; } else if (operator == '-') { return number1 - number2; } else if (operator == '*') { return number1 * number2; } else if (operator == '/' && number2 != 0) { return number1 / number2; } else { return -1; } } private static ArrayList<String> search() { //声明一个ArrayList,用于存放所有可能的表达式 ArrayList<String> expressionList = new ArrayList<String>(); // 第一次放置的符号(算术优先级最高) for (int i = 0; i < 4; i++) { // 第二次放置的符号(算术优先级次高) for (int j = 0; j < 4; j++) { // 第三次放置的符号(最后一个计算) for (int k = 0; k < 4; k++) { // 首先计算的两个相邻数字,共有3种情况,相当于括号的作用,也就是各种优先级顺序组合 for (int m = 0; m < 3; m++) { // 如果出现除数为零则表达式出错,结束此次循环 if (scard[m + 1] == 0 && operator[i] == '/') { break; } // 从4个操作数中提取出两个数,然后将可能进行优先计算的两个数计算,然后得到值,注意:这里是优先级最高的运算符,也就是第一次放置的符号 temp1[m] = calcute(scard[m], scard[m + 1], operator[i]); // 将其余两个没有进行计算的值赋值给temp1数组 temp1[(m + 1) % 3] = scard[(m + 2) % 4]; temp1[(m + 2) % 3] = scard[(m + 3) % 4]; // 先确定首先计算的两个数字,计算完成相当于剩下三个数,按顺序储存在temp1数组中 // 三个数字选出先计算的两个相邻数字,两种情况,相当于第二个括号 for (int n = 0; n < 2; n++) { if (temp1[n + 1] == 0 && operator[j] == '/') { break; } // 简化运算,将三个操作数简化为两个操作数,注意:这里是优先级最高的运算符,也就是第二次放置的符号 temp2[n] = calcute(temp1[n], temp1[n + 1], operator[j]); temp2[(n + 1) % 2] = temp1[(n + 2) % 3]; if (temp2[1] == 0 && operator[k] == '/') { break; } // 将两个操作数简化为一个操作数,注意:这里是优先级最高的运算符,也就是第三次放置的符号 sum = calcute(temp2[0], temp2[1], operator[k]); // 如果能够24,那么将该算式输出来 if (sum == 24) { isCorrect = true; String expression = ""; // 根据组合列出算式 if (m == 0 && n == 0) { expression = "((" + (int) scard[0] + operator[i] + (int) scard[1] + ")" + operator[j] + (int) scard[2] + ")" + operator[k] + (int) scard[3] + "=" + (int) sum; } else if (m == 0 && n == 1) { expression = "(" + (int) scard[0] + operator[i] + (int) scard[1] + ")" + operator[k] + "(" + (int) scard[2] + operator[j] + (int) scard[3] + ")=" + (int) sum; } else if (m == 1 && n == 0) { expression = "(" + (int) scard[0] + operator[j] + "(" + (int) scard[1] + operator[i] + (int) scard[2] + "))" + operator[k] + (int) scard[3] + "=" + (int) sum; } else if (m == 2 && n == 0) { expression = "(" + (int) scard[0] + operator[j] + (int) scard[1] + ")" + operator[k] + "(" + (int) scard[2] + operator[i] + (int) scard[3] + ")=" + (int) sum; } else if (m == 2 && n == 0) { expression = (int) scard[0] + operator[k] + "(" + (int) scard[1] + operator[j] + "(" + (int) scard[2] + operator[i] + (int) scard[3] + "))=" + (int) sum; } System.out.println(expression); expressionList.add(expression); } } } } } } return expressionList; } /** * 利用对花色的排列组合,避免花色重复,大量地减少运算量,提高效率 * @param i * @param j * @param k * @param l * @return */ private static int times(int i,int j,int k,int l){ //利用set判断有多少种重复 Set<Integer> set =new HashSet<Integer>(); set.add(i); set.add(j); set.add(k); set.add(l); //当4个数的数字全部一样时,只可能有一种花色的组合,比如红桃6,梅花6,方块6,黑桃6 if(set.size()==1){ return 1; } //当4个数中,有两个数相同,其余的数都不相同时,就有C4取2乘以C4取1乘以C4取1种可能的花色组合,比如红桃6,梅花6,方块7,黑桃8 else if(set.size()==3){ return 96; } //当4个数全部不同时,就有C4取1乘以C4取1乘以C4取1乘以C4取1种(256)情况 else if(set.size()==4){ return 256; } else{ //当4个数中,两两相同时,同样的,利用排列组合,一共有C4取2乘以C4取2,共36种情况 if((i==j&&k==l)||(i==k&&j==l)){ return 36; } //当4个数中有三个数相同,另外一个数不同时 else { return 16; } } }}
- 24点算法详解--Java代码实现
- java实现24点算法
- 24点算法的java代码
- java经典24点算法代码
- PageRank算法及Java代码实现(代码有详解)
- 关于24点算法的思想和代码实现
- 24点算法实现
- 24点java代码
- 现代应用密码学中椭圆曲线求点集E以及点乘算法的java代码实现
- 扑克牌计算24点的Java算法实现
- C++实现24点算法
- java排序算法实现代码
- java排列组合算法代码实现
- java排列组合算法代码实现
- TFIDF算法,java代码实现
- HITS算法详解及代码实现
- C45算法代码实现及其详解
- opencv实现camshift算法,以及代码详解
- CSS3实现动态翻牌效果 仿百度贴吧3D翻牌一次动画特效
- 数据结构课程总结
- 嵌入式 hi3518平台uboot引导nfs文件系统
- Object的equals方法
- vue.js
- 24点算法详解--Java代码实现
- 《数字技术》连载31:第4章 信息传输的控制和选择 第4节 多路选择器
- 九次方华东区总经理姚乐生:大数据建设要结合地方产业
- Eclipse 卡死在 Android SDK Content Loader
- 普元信息政务大数据咨询顾问夏佳斌:数据资源体系的核心——资源定义、运营机制和支撑平台
- 专访泰康大数据部总经理周雄志:“经验驱动”成为过去式,“数据驱动”基本实现
- java实现定时任务的三种常用方法
- SODA理事会理事、苏打数据CEO高丰:只有数据流通,数据才能创造价值
- C++之引用