Java 24 点 杭电1427

最近一时兴起,刷了一些杭电的题目。其中24 点这个题目花了我不少时间,差不多两个多小时才AC。故特此记录。

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1427


Problem Description
速算24点相信绝大多数人都玩过。就是随机给你四张牌,包括A(1),2,3,4,5,6,7,8,9,10,J(11),Q(12),K(13)。要求只用'+','-','*','/'运算符以及括号改变运算顺序,使得最终运算结果为24(每个数必须且仅能用一次)。游戏很简单,但遇到无解的情况往往让人很郁闷。你的任务就是针对每一组随机产生的四张牌,判断是否有解。我们另外规定,整个计算过程中都不能出现小数。
 
Input
每组输入数据占一行,给定四张牌。
 
Output
每一组输入数据对应一行输出。如果有解则输出"Yes",无解则输出"No"。
 
Sample Input
  
  
A 2 3 6 3 3 8 8
 
Sample Output
  
  
Yes No

思路

深搜当然是最佳策略,但是对于一个算法渣来说并不是我的最佳选择。

我的思路:拿到四个数,全排序,然后处理括号,计算所有操作符的组合情况。


全排序:A44, 共24 种组合。

处理括号:在只有四个数的情况下,括号还算比较好处理。

除了顺序计算四个数,也就是 ((a * b)* c)* d 之外(*可以是任何操作符),

只需要考虑 (a* b)* (c* d) ,以及 a * (b * c) * d  一共三种计算顺序。就可以涵盖所有括号能够带来的可能性。

操作符计算:涵盖加减乘除四种操作符即可。注意的是,除法不能产生小数。


打表

但是!全排序的性能和深搜天差地别,这么做正确性可以保证了,但是会超时。

所以,我选择打表的方式。

打表很简单,把所有不能计算出24 点的组合硬编码下来。

选择不能计算的:不能计算出24 点的组合(20%左右)比能计算出的组合少很多。

编码方式:用数组记录,a * 14 * 14 * 14 + b * 14 * 14 + c * 14 + d * 14. 如果采用100 作为因子的话,java 代码会编译不过,代码超长。

编码优化:我们不需要把一种牌的,所有组合都硬编码下来,只需要排序之后再记录即可。


注意事项:

1. 输入的数据中,10 是唯一一个两位数字,如果使用java 以外的代码实现的话,需要注意。

2. 输出的格式,"Yes" 和 "No"。

3. 括号,括号可以涵盖两种计算模式:(a * b) * (c * d) ,以及 a * (b * c) * d,不要遗漏了。

4. 除法不能产生小数。


测试数据:

易错数据,结果全是"Yes":
10 10 4 4
8 9 Q 9
6 8 1 1
5 5 5 5
3 3 3 9
常规测试数据:
5 Q 2 J
5 J 3 3
3 J 6 9
8 7 9 Q
5 6 Q 10
9 6 9 9
2 10 3 2
4 5 6 2
4 9 J 4
10 A 4 J
10 A 8 4
3 2 Q Q
4 10 10 8
Q 4 2 A
3 2 A 10
K 9 A J
7 9 10 Q
9 9 4 K
8 K K 6
5 K A 9

答案:
Yes
No
Yes
Yes
Yes
No
Yes
Yes
Yes
Yes
No
Yes
Yes
Yes
Yes
Yes
Yes
No
Yes
Yes


代码:

import java.util.*;

/**
 * Created by jz on 2017/4/13.
 * 10 10 4 4
 * 8 9 Q 9
 * 6 8 1 1
 * 5 5 5 5
 * 3 3 3 9
 */
public class Main {

    public static void main(String[] args) {
        HashSet<Integer> brokenGroup = getBrokenGroups();
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()) {
            int a = getNumber(scanner.next());
            int b = getNumber(scanner.next());
            int c = getNumber(scanner.next());
            int d = getNumber(scanner.next());
            boolean broken = brokenGroup.contains(encodeCards(a, b, c, d));
            System.out.println(broken? "No" : "Yes");
//            int[] list = {a, b, c, d};
//            System.out.println(judge(list) ? "Yes" : "No");
        }
    }

    public static HashSet<Integer> getBrokenGroups() {
        Integer[] list = {2955,2956,2957,2958,2959,2960,2961,2963,2964,2970,2971,2972,2973,2985,3007,3009,3019,3020,3021,3022,3023,3031,3034,3035,3037,3045,3046,3047,3049,3050,3051,3061,3062,3063,3064,3065,3075,3076,3077,3078,3090,3091,3166,3167,3217,3247,3259,3260,3271,3272,3286,3387,3394,3407,3441,3485,3499,3597,3604,3636,3650,3663,3681,3693,3694,3695,3709,3723,3799,3801,3802,3829,3891,3905,3919,4011,4012,4025,4026,4031,4057,4070,4071,4085,4115,4221,4222,4227,4241,4266,4267,4281,4282,4283,4437,4447,4448,4462,4477,4492,4493,4507,4643,4644,4645,4647,4658,4659,4689,4703,4854,4855,4857,4869,4871,4899,5065,5487,5910,5914,5963,5987,5989,6003,6005,6015,6019,6032,6045,6075,6122,6158,6213,6227,6383,6409,6422,6439,6453,6543,6544,6548,6578,6603,6607,6633,6635,6663,6769,6803,6829,6859,6965,6967,6968,6982,6995,6998,7013,7025,7027,7055,7223,7387,7388,7418,7432,7598,7628,7643,8875,8886,8898,8901,8925,8928,8940,8943,8970,8971,8972,8985,9015,9107,9127,9136,9152,9167,9181,9211,9287,9292,9295,9317,9334,9349,9379,9517,9531,9561,9713,9726,9756,9771,9925,9953,9967,10342,10343,10345,10357,10372,10373,10387,10553,10555,10569,10583,10975,11829,11839,11850,11851,11865,11869,11895,11896,11899,11911,11925,11955,12037,12038,12039,12093,12247,12249,12261,12263,12275,12289,12305,12319,12455,12456,12458,12459,12501,12697,12875,12877,12879,12890,12907,12921,12935,13086,13089,13101,13131,13297,13298,13299,13312,13327,13509,13523,13719,14777,14778,14780,14781,14783,14793,14794,14796,14797,14807,14809,14810,14811,14838,14839,14852,14991,14993,15004,15005,15019,15197,15198,15201,15202,15203,15215,15216,15217,15227,15258,15273,15411,15412,15423,15424,15438,15441,15453,15469,15483,15619,15620,15623,15636,15649,15650,15679,15830,15846,15847,15860,16041,16042,16043,16057,16071,16252,16253,16267,16463,17731,17737,17745,17746,17751,17775,17790,17791,17805,17835,17941,17942,17943,17946,17947,17956,17961,17972,17973,17975,17987,18031,18157,18182,18213,18363,18367,18378,18381,18393,18423,18575,18576,18589,18591,18619,18785,18787,18815,19207,20685,20686,20687,20688,20689,20691,20700,20701,20702,20704,20705,20715,20717,20718,20719,20730,20731,20732,20745,20775,20896,20911,20913,20928,20941,20971,21107,21108,21109,21110,21122,21125,21139,21153,21318,21321,21333,21334,21363,21529,21530,21531,21544,21545,21559,21740,21755,21951,23640,23641,23655,23656,23670,23671,23685,23715,23851,23852,23853,23855,23866,23867,23911,24062,24063,24065,24078,24079,24273,24274,24275,24289,24303,24484,24485,24499,24695,26595,26596,26597,26599,26610,26611,26612,26625,26655,26806,26807,26808,26821,26851,27018,27019,27229,27243,27439,29550,29551,29565,29595,29761,29791,32505,32535,38415,};
        HashSet<Integer> brokenGroups = new HashSet<Integer>();
        Collections.addAll(brokenGroups, list);
        return brokenGroups;
    }

    /**
     * create encode list
     */
    public static HashSet<Integer> createBrokenGroups() {
        HashSet<Integer> brokenGroup = new HashSet<Integer>();
        for (int a = 1 ; a <= 13 ; a++) {
            for (int b = a ; b <= 13 ; b++) {
                for (int c = b ; c <= 13 ; c++) {
                    for (int d = c ; d <= 13 ; d++) {
                        int[] list = {a, b, c, d};
                        if (!judge(list)) {
                            int encodedNum = encodeCards(a, b, c, d);
                            System.out.print(encodedNum + ",");
                            brokenGroup.add(encodedNum);
                        }
                    }
                }
            }
        }
        return brokenGroup;
    }

    public static int encodeCards(int a, int b, int c, int d) {
        // bubble sort firstly
        int[] list = {a, b, c, d};
        for (int i = 0 ; i < list.length ; i++) {
            for (int inner = 0 ; inner < list.length - 1 - i ; inner++) {
                if (list[inner] > list[inner + 1]) {
                    int temp = list[inner];
                    list[inner] = list[inner + 1];
                    list[inner + 1] = temp;
                }
            }
        }
        // encode
        int factor = 14;
        return list[3] + factor * list[2] + factor * factor * list[1] + factor * factor * factor * list[0];
    }

    public static int getNumber(String card) {
        switch (card) {
            case "A":
                return 1;
            case "J":
                return 11;
            case "Q":
                return 12;
            case "K":
                return 13;
            default:
                return Integer.parseInt(card);
        }
    }

    public static boolean judge(int[] fourNumber) {
        for (int[] list : forforfor(fourNumber)) {
            if (caculate(list)) {
//                System.out.println(result);
                return true;
            }
        }
        return false;
    }

    protected static ArrayList<int[]> forforfor(int[] list) {
        ArrayList<int[]> orderedList = new ArrayList<int[]>();
        for (int a = 0 ; a < 4 ; a++) {
            for (int b = 0 ; b < 4 ; b++) {
                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;
//                        System.out.println(list[a] + " " + list[b] + " " + list[c] + " " + list[d]);
                        int[] temp = {list[a], list[b], list[c], list[d]};
                        orderedList.add(temp);
                    }
                }
            }
        }
        return orderedList;
    }

    protected static boolean caculate(int[] numbers) {
        StringBuffer sb = new StringBuffer();
        for (int firstIndex = 1 ; firstIndex <= 4 ; firstIndex++) {
            for (int secondIndex = 1 ; secondIndex <= 4 ; secondIndex++) {
                for (int thirdIndex = 1 ; thirdIndex <= 4 ; thirdIndex++) {
                    int currentResult = 0;
                    try {
                        currentResult = caculateTwo(caculateTwo(caculateTwo(
                                numbers[0], numbers[1], firstIndex), numbers[2], secondIndex), numbers[3], thirdIndex);
                        if (currentResult == 24) {
                            return true;
                        }
                    } catch (RuntimeException e) {
                        // continue calculating pattern like (5 * 5) - (5 / 5)
                    }
                    try {
                        currentResult = caculateTwo(caculateTwo(numbers[0], numbers[1], firstIndex), caculateTwo(numbers[2], numbers[3], secondIndex), thirdIndex);
                        if (currentResult == 24) {
                            return true;
                        }
                    } catch (RuntimeException e) {
                        // continue calculating pattern like (9 - (3 / 3)) * 3
                    }
                    try {
                        currentResult = caculateTwo(caculateTwo(numbers[0], caculateTwo(numbers[1], numbers[2], secondIndex), firstIndex), numbers[3], thirdIndex);
                        if (currentResult == 24) {
                            return true;
                        }
                    } catch (RuntimeException e) {
                        continue;
                    }
                }
            }
        }
        return false;
    }

    protected static int caculateTwo(int a, int b, int operator) {
        switch (operator) {
            case 1:
                return a + b;
            case 2:
                return a - b;
            case 3:
                return a * b;
            case 4:
                if (a % b != 0) {
                    throw new RuntimeException();
                } else {
                    return a / b;
                }
            default:
                throw new RuntimeException("Invalid operator " + operator);
        }
    }
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值