最近一时兴起,刷了一些杭电的题目。其中24 点这个题目花了我不少时间,差不多两个多小时才AC。故特此记录。
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1427
思路
深搜当然是最佳策略,但是对于一个算法渣来说并不是我的最佳选择。
我的思路:拿到四个数,全排序,然后处理括号,计算所有操作符的组合情况。
全排序: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 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 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 brokenGroups = new HashSet();
Collections.addAll(brokenGroups, list);
return brokenGroups;
}
/**
* create encode list
*/
public static HashSet createBrokenGroups() {
HashSet brokenGroup = new HashSet();
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 forforfor(int[] list) {
ArrayList orderedList = new ArrayList();
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);
}
}
}