24点的一种暴力实现

计算24点是一种扑克牌益智游戏,随机抽出4张扑克牌,通过加(+),减(-),乘(*), 除(/)四种运算法则计算得到整数24,本问题中,扑克牌通过如下字符或者字符串表示:

             A 2 3 4 5 6 7 8 9 10 J Q K

程序要求实现:输入4张牌,判断能否通过四则运算得到24点。

在网上没找到什么好的算法,最后选择了暴力遍历,思路如下:
字母到数字的转换比较简单,这里不做介绍,并认为输入的数据为数字,即摸到K的时候输出13

  1. 先从4个数中任选2个数做±/,得到结果集A
    如:输入4个数(1 2 3 4),取其中的1,2做四则运算,得到A为
    (1-2,1+2,1
    2,1/2)->(-1,3,2,0.5)
  2. 遍历A,与step1中剩余两个数组成一个长度为A.size()的List记为ret4
    遍历A,与剩余两个数组合,得到ret4为(-1,3,4),(3,3,4),(0.5,3,4)……
  3. 类似的,遍历ret4,从3个数中,取任意两个数做±*/,得到结果集B
  4. 遍历结果集B,与step3中剩余的一个数组成长度为B.size()的List记为ret3
  5. 遍历ret3,对这两个数做±*/操作,得到的结果集存入ret2
  6. 若ret2.contains(24)则可以得到24点,否则不能

下面上代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @Author Jeb
 * @Date 2020/4/3
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            // 读取四个数存入inl中
            List<Double> inl = new ArrayList<>();
            for (int i = 0; i < 4; i++) {
                inl.add(sc.nextDouble());
            }
            //四个数任取两个做+-*/运算,运算结果与剩余两个数组成一个3个数的List,将这些List存入ret4中
            //如1 2 3 4,取2和4做运算,则得到一个{{1,3,2+4},{1,3,2-4},{1,3,2*4},{1,3,2/4}}的集合
            List<List<Double>> ret4 = new ArrayList<>();
            //三个数任取两个做+-*/运算,运算结果与剩余一个数组成一个2个数的List,将这些两个数的List存入ret3中
            List<List<Double>> ret3 = new ArrayList<>();
            //对两个数做+-*/运算,运算结果存入ret2中
            List<Double> ret2 = new ArrayList<>();

            cal4(inl, ret4);
            cal3(ret4,ret3);
            cal2(ret3,ret2);
            System.out.println(ret2.contains(new Double("24")));
        }
    }

    /**
     * 输入一个长度为4的List,任取两个数做+ - * /运算,结果与剩余两个数组成3个数的List存入ret中
     * @param inl 4个数字组成的List<Double>
     * @param ret 3个数组成的List<Double>的集合
     */
    public static void cal4(List<Double> inl,List<List<Double>> ret) {
        //遍历输入inl,以实现取任意一个数的情况
        for (int i = 0; i < inl.size(); i++) {
            //取遍历值
            Double l = inl.get(i);
            Double r;
            //以inl为基础建立一个副本
            List<Double> tmp = new ArrayList<>(inl);
            //删除已经出去的元素,得到剩余三个元素的集合
            //如inl:{1,2,3,4},取出1后,得到一个剩余三个元素的tmp:{2,3,4}
            tmp.remove(inl.get(i));
            //遍历tmp以实现取剩余三个数中任意一个数的情况
            for (int j = 0; j < tmp.size(); j++) {
                r = tmp.get(j);
                //以tmp为基础建立一个副本
                List<Double> tmp1 = new ArrayList<>(tmp);
                //删除已经取出的元素,得到剩余两个元素的集合
                //如tmp:{2,3,4},取出2后,得到一个剩余2个元素的tmp1:{3,4}
                tmp1.remove(r);
                //l,r做+-*/四则运算后存入asmdList
                List<Double> asmdList = asmd(l,r);
                // 遍历asmdList
                for(Double asmd:asmdList) {
                    //分别将每个四则运算结果加入tmp1中,组成一个3个元素的List
                    tmp1.add(asmd);
                    //将3个元素的List添加到ret中
                    ret.add(new ArrayList<>(tmp1));
                    //还原tmp1到未添加四则运算结果时的状态,以便下一循环的添加
                    tmp1.remove(asmd);
                }
            }
        }

    }

    /**
     * 输入一个长度为3的List,任取两个数做+ - * /运算,结果与剩余一个数组成3个数的List存入ret中
     * @param inl 3个数字组成的List<Double>的集合
     * @param ret 2个数组成的List<Double>的集合
     */
    public static void cal3(List<List<Double>> inl,List<List<Double>> ret) {
        for(List<Double> singlel : inl) {
            for (int i = 0; i < singlel.size(); i++) {
                Double l = singlel.get(i);
                Double r;
                List<Double> tmp = new ArrayList<>(singlel);
                tmp.remove(singlel.get(i));
                for (int j = 0; j < tmp.size(); j++) {
                    r = tmp.get(j);
                    List<Double> tmp1 = new ArrayList<>(tmp);
                    tmp1.remove(r);
                    //l,r做+-*/四则运算后存入t
                    List<Double> asmdList = asmd(l,r);
                    for(Double asmd:asmdList) {
                        tmp1.add(asmd);
                        ret.add(new ArrayList<>(tmp1));
                        tmp1.remove(asmd);
                    }
                }
            }
        }
    }

    /**
     * 输入一个长度为2的List,任取两个数做+ - * /运算,结果存入ret中
     * @param inl 2个数字组成的List<Double>的集合
     * @param ret 两个数做+ - * /的结果集合
     */
    public static void cal2(List<List<Double>> inl,List<Double> ret) {
        for(List<Double> singlel : inl) {
            ret.addAll(asmd(singlel.get(0),singlel.get(1)));
            ret.addAll(asmd(singlel.get(1),singlel.get(0)));
        }
    }


    public static List<Double> asmd(Double l,Double r) {
        List<Double> ret = new ArrayList<>();
        for (int k = 0; k < 4; k++) {
            switch (k) {
                case 0:
                    ret.add(l + r);
                    break;
                case 1:
                    ret.add(l - r);
                    break;
                case 2:
                    ret.add(l * r);
                    break;
                case 3:
                    if (r != 0) {
                        ret.add(l / r);
                    }
                    break;
                default:
                    break;
            }
        }
        return ret;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JebWoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值